package com.cloudkinto.service.fbaorderoutput.impl;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.DicBusinessConstant;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.error.ErrorEnum;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.exception.BizExceptionI18;
import com.cloudkinto.common.exception.NotSufficientFundsException;
import com.cloudkinto.common.utils.*;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.dic.DicBusinessItemService;
import com.cloudkinto.service.dic.vo.DicItemRes;
import com.cloudkinto.service.email.MailSenderService;
import com.cloudkinto.service.fbaaaaaa.TailTrucksService;
import com.cloudkinto.service.fbaorderoutput.FbaOrderOutputService;
import com.cloudkinto.service.fbaorderoutput.vo.*;
import com.cloudkinto.service.file.FileService;
import com.cloudkinto.service.finance.CompanyAccountService;
import com.cloudkinto.service.finance.vo.IdAndNameEntity;
import com.cloudkinto.service.operate.OperateRecordService;
import com.cloudkinto.service.operate.vo.OperateRes;
import com.cloudkinto.service.orderback.OrderBackService;
import com.cloudkinto.service.orderback.vo.OrderBackAddItem;
import com.cloudkinto.service.orderback.vo.OrderBackAddReq;
import com.cloudkinto.service.orderinput.OrderInputService;
import com.cloudkinto.service.orderoutput.vo.FbaShipPriceRes;
import com.cloudkinto.service.orderoutput.vo.OrderOutputAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputExcelReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputProductAddReq;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.shipprice.ShipPriceService;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.service.stock.StockRecordService;
import com.cloudkinto.service.stock.vo.record.StockRecordPageRes;
import com.cloudkinto.service.storage.StorageService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author 张永远
 * @since 2020-06-04
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class FbaOrderOutputServiceImpl extends ServiceImpl<FbaOrderOutputDao, FbaOrderOutputDo> implements FbaOrderOutputService {
    private static final String SHIPMENT_TYPE_0 = "普通";
    private static final String SHIPMENT_TYPE_1 = "次日达";
    private static final String ORDER_OUTPUT_TYPE_2 = "FBA转运";
    private static final String ORDER_OUTPUT_TYPE_1 = "一件代发";
    @Autowired
    private FbaOrderOutputDao dao;
    @Autowired
    private ProductInfoDao productInfoDao;
    @Autowired
    private FbaOrderOutputPackageDao packageDao;
    @Autowired
    private FbaOrderOutputProductDao productDao;
    @Autowired
    private OrderAmazonDao amazonDao;
    @Autowired
    private OrderRakutenDao rakutenDao;
    @Autowired
    private ShopDao shopDao;
    @Autowired
    private StorageService storageService;
    @Autowired
    private JpRegionService regionService;
    @Autowired
    private ProductSkuMapDao productSkuMapDao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private DicBusinessItemDao dicBusinessItemDao;
    @Autowired
    private DicBusinessItemService dicBusinessItemService;
    @Autowired
    private ShipPriceService mShipPriceService;
    @Autowired
    private StockRecordDao mStockRecordDao;
    @Autowired
    private CompanyDao mCompanyDao;
    @Autowired
    private DimensDao mDiminDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private ShopService shopService;
    @Autowired
    private OperateRecordDao operateRecordDao;
    @Autowired
    private OperateRecordService operateRecordService;
    @Autowired
    private CompanyAccountService companyAccountService;
    @Autowired
    private FileService fileService;
    @Autowired
    private OrderBackService orderBackService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private MailSenderService mailSenderService;
    @Autowired
    private OrderQoo10Dao qoo10Dao;
    @Autowired
    private FbaStorageDao fbaStorageDao;
    @Autowired
    private FbaDimensDao fbaDimensDao;
    @Autowired
    private FbaShipPriceDao fbaShipPriceDao;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private StockRecordDao stockRecordDao;
    @Autowired
    private TailTrucksService tailTrunkService;
    @Autowired
    private OrderInputDao orderInputDao;
    @Autowired
    private OrderInputPackageDao orderInputPackageDao;
    @Autowired
    private OrderInputProductDao orderInputProductDao;
    @Autowired
    private OrderInputService orderInputService;
    @Autowired
    private ShippingAddressDao shippingAddressDao;
    @Autowired
    private StockRecordService stockRecordService;


    private final int[] sizeArr = new int[]{5, 10, 20, 30, 40, 60, 80, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400};


    @Override
    public SingleResult addInit(Long currentUserId, Long companyId) {
        Map map = new HashMap();
        map.put("storageList", storageService.getJpList());
        map.put("regionList", regionService.getList(new HashMap<>()));
        map.put("shopList", shopService.selectShopListInit(currentUserId, companyId));
        LambdaQueryWrapper<DicBusinessItemDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.fbaOrderOutPutTruck);
        List<DicBusinessItemDo> trackCompanyList = dicBusinessItemDao.selectList(wrapper);
        List<IdAndNameEntity> trackList = new ArrayList<>();
        for (DicBusinessItemDo itemDo :
                trackCompanyList) {
            trackList.add(new IdAndNameEntity(itemDo.getId().intValue(), itemDo.getDicItemValue()));
        }
        map.put("trackList", trackList);


        //fbaStorage
        QueryWrapper wrapper1 = new QueryWrapper();
        wrapper1.orderByAsc("fba_code");
        List<FbaStorageDo> fbaStorageDos = fbaStorageDao.selectList(wrapper1);
        List<Map> fbaStorageList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(fbaStorageDos)) {
            fbaStorageDos.forEach(fbaStorageDo -> {
                Map fbaMap = new HashMap();
                fbaMap.put("id", fbaStorageDo.getId());
                fbaMap.put("code", fbaStorageDo.getFbaCode());
                fbaMap.put("name", fbaStorageDo.getFbaName());
                fbaMap.put("address", fbaStorageDo.getAddress());
                fbaMap.put("postCode", fbaStorageDo.getPostCode());
                fbaMap.put("tel", fbaStorageDo.getTelPhone());
                fbaStorageList.add(fbaMap);
            });
        }
        map.put("fbaStorageList", fbaStorageList);


        List<ShippingAddressDo> addressList = shippingAddressDao.selectList(new QueryWrapper<ShippingAddressDo>().eq("company_id", companyId));
        List<Map> resList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(addressList)) {
            addressList.forEach(addressDo -> {
                Map map1 = new HashMap();
                map1.put("id", addressDo.getId());
                map1.put("name", addressDo.getContact());
                map1.put("companyName", addressDo.getCompanyName());
                map1.put("address", addressDo.getAddress());
                map1.put("postCode", addressDo.getPostCode());
                map1.put("tel", addressDo.getTelPhone());
                resList.add(map1);
            });
        }
        map.put("ownAddressList", resList);

        List<Map> productTypeList = new ArrayList<>();
        LambdaQueryWrapper<DicBusinessItemDo> wrapperProductType = new LambdaQueryWrapper<>();
        wrapperProductType.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.productType);
        List<DicBusinessItemDo> businessItemDoList = dicBusinessItemDao.selectList(wrapperProductType);
        if (!CollectionUtils.isEmpty(businessItemDoList)) {
            for (DicBusinessItemDo businessItemDo : businessItemDoList) {
                Map mapProductType = new HashMap();
                mapProductType.put("id", businessItemDo.getId());
                mapProductType.put("value", businessItemDo.getDicItemValue());
                productTypeList.add(mapProductType);
            }
        }
        map.put("productTypeList", productTypeList);

        return SingleResult.success(map);
    }


    @Override
    public String fbaStorageAdd(FbaOrderOutputAddReq req, Long userId) {
        sufficientFundsCheck(req.getCompanyId());
        addCheck(req);
        FbaOrderOutputDo entityDo = new FbaOrderOutputDo();
        if (req.getStorageType().equals(SysConstant.FBA_ADDRESS)) {
            FbaStorageDo fbaStorageDo = fbaStorageDao.selectById(req.getFbaStorageId());
            if (StringUtils.isBlank(req.getAddress())) {
                req.setAddress(fbaStorageDo.getAddress());
            }
            if (StringUtils.isBlank(req.getPostCode())) {
                req.setPostCode(fbaStorageDo.getPostCode());
            }
            if (StringUtils.isBlank(req.getReceiverName())) {
                req.setReceiverName(fbaStorageDo.getFbaName());
            }
            if (StringUtils.isBlank(req.getTelPhone())) {
                req.setTelPhone(fbaStorageDo.getTelPhone());
            }
        } else {
            ShippingAddressDo fbaStorageDo = shippingAddressDao.selectById(req.getFbaStorageId());
            if (fbaStorageDo != null) {
                if (StringUtils.isBlank(req.getAddress())) {
                    req.setAddress(fbaStorageDo.getAddress());
                }
                if (StringUtils.isBlank(req.getPostCode())) {
                    req.setPostCode(fbaStorageDo.getPostCode());
                }
                if (StringUtils.isBlank(req.getReceiverName())) {
                    req.setReceiverName(fbaStorageDo.getCompanyName());
                }
                if (StringUtils.isBlank(req.getTelPhone())) {
                    req.setTelPhone(fbaStorageDo.getTelPhone());
                }
            }
        }
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setShipFee(req.getShipFee());

        entityDo.setShipFee(req.getShipFee());
        if (StringUtils.isNotBlank(req.getDeliveryDate())) {
            entityDo.setDeliveryDate(TimeUtils.parseDate(req.getDeliveryDate()));
        }
        handlerAddBefore(entityDo, userId);
        if (StringUtils.isNotBlank(req.getStorageType())) {
            entityDo.setStorageType(req.getStorageType());
        } else {
            entityDo.setStorageType("fba");
        }
        dao.insert(entityDo);
        handlerFbaStorageAdd(entityDo, req.getFileId(), req.getProductFileId(), req.getTrackId(), req.getPackageList(), userId);
        entityDo.setFbaOrderOutputNumber(OrderCodeUtil.getFbaOrderOutputNumber(entityDo.getId()));
        entityDo.setTrackId(req.getTrackId());
        //todo 判断是否有足额
        verfiyCurrentAmount(entityDo.getOutFee() + entityDo.getShipFee() + entityDo.getOperateFee() + entityDo.getTaxFee(), entityDo.getCompanyId(), entityDo.getId());
        dao.updateById(entityDo);
        //计算费用
//        handlerFee(entityDo);

        //日志操作
        operateRecordService.operateAddRecord(SysConstant.OPERATE_CREATE_FBA, entityDo.getId(), userId, 6);

        fileService.uploadFile(req.getFileId());
        fileService.uploadFile(req.getProductFileId());
        fileService.uploadFile(req.getOtherFileId());

        LambdaQueryWrapper<OrderInputDo> orderInputWrapper = new LambdaQueryWrapper<>();
        orderInputWrapper.eq(OrderInputDo::getOrderInputNumber, entityDo.getOrderInputNumber());
        OrderInputDo orderInputDo = orderInputDao.selectOne(orderInputWrapper);
        if (orderInputDo != null) {
            if (orderInputDo.getStatus().equals(DicBusinessItemConstant.inPutStorage)) {
                orderInputService.handlerStockCount(orderInputDo, userId);
            }
            orderInputDo.setStatus(DicBusinessItemConstant.inPutTurnFba);
            orderInputDo.setUpdateBy(userId);
            orderInputDo.setUpdateTime(new Date());
            orderInputDo.setInputBy(userId);
            orderInputDo.setInputTime(new Date());
            operateRecordService.operateAddRecord(SysConstant.OPERATE_TURN_FBA_ORDER, orderInputDo.getId(), userId, 2);

            orderInputDao.updateById(orderInputDo);
        }
        if (entityDo.getTrackId() < DicBusinessItemConstant.fbaTrackName2t) {
            return null;
        }
        threadPoolTaskExecutor.execute(() -> {
//            tailTrunkService.jointFbaTrucks(entityDo.getId(), userId);
        });
        return null;
    }

    private void verfiyCurrentAmount(double cost, Long companyId, Long id) {
        LambdaQueryWrapper<CompanyAccountDo> companyAccounWrapper = new LambdaQueryWrapper<>();
        companyAccounWrapper.eq(CompanyAccountDo::getCompanyId, companyId);
        CompanyAccountDo accountDo = companyAccountService.getBaseMapper().selectOne(companyAccounWrapper);
        if (accountDo == null) {
            throw new NotSufficientFundsException();
        }
        if (accountDo.getCreateTime() == null) {
            return;
        }
        if (accountDo.getCreateTime().getTime() > TimeUtils.parseDate("2021-03-01").getTime()) {
            double waitOutCost = 0;
            double canUseAmount = 0;
            LambdaQueryWrapper<FbaOrderOutputDo> wrapper = new LambdaQueryWrapper<>();
            wrapper.lt(FbaOrderOutputDo::getStatus, DicBusinessItemConstant.fbaOrderSendOutStatus)
                    .eq(FbaOrderOutputDo::getCompanyId, companyId)
                    .ne(FbaOrderOutputDo::getId, id);
            List<FbaOrderOutputDo> fbaOrderOutputDoList = baseMapper.selectList(wrapper);
            if (fbaOrderOutputDoList != null) {
                waitOutCost = fbaOrderOutputDoList.stream().mapToDouble(value ->
                        value.getTaxFee() + value.getOperateFee() + value.getShipFee() + value.getOutFee()).sum();
            } else {
                waitOutCost = 0;
            }
            canUseAmount = accountDo.getCompanyAccount() - waitOutCost + accountDo.getMaxLimit();
            if (cost - canUseAmount > 500) {
                throw new BizException(SysConstant.ACCOUNT_MONEY_LESS, canUseAmount, cost);
            }
        }
    }

    @Override
    public List<Map> computationalCosts(FbaOrderOutputComputationalCostsReq req, Long companyId) {
        if (req.getFbaStorageId() == null && req.getPostCode() == null) {
            return null;
        }
        List<Map> priceList = new ArrayList<>();

        LambdaQueryWrapper<DicBusinessItemDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.fbaOrderOutPutTruck);
        List<DicBusinessItemDo> businessItemDoList = dicBusinessItemDao.selectList(wrapper);
        for (int i = 0; i < businessItemDoList.size(); i++) {
            handlerFee(req, businessItemDoList.get(i), companyId, priceList, i);
        }
        return priceList;
    }


    private void handlerFee(FbaOrderOutputComputationalCostsReq req, DicBusinessItemDo businessItemDo, Long companyId, List<Map> priceList, int index) {
        double totalPriceBySize = 0;
        double totalPriceByVolume = 0;

        //计算总体积 总尺寸
        double maxSize = 0;//包裹最大尺寸
        double maxWeight = 0; //包裹最大重量
        double totalVolume = req.getPackageAddReqList().stream()
                .mapToDouble(packageAddReq -> packageAddReq.getHeight() * packageAddReq.getWidth() * packageAddReq.getLength() / 1000000 * packageAddReq.getPackageCount()).sum();
        //        double totalVolumeAndWeight = 0;
        double totalWeight = req.getPackageAddReqList().stream()
                .mapToDouble(packageAddReq -> packageAddReq.getWeight() * packageAddReq.getPackageCount()).sum();
        //如果flag为true表示 有的包裹价格匹配不上，则 不展示该快递公司的 运算价格
        boolean sizeFlag = false;
        boolean volumeFlag = false;

        CompanyDo companyDo = companyDao.selectById(companyId);
        Long fbaStorageId = getFbaStorageId(req.getFbaStorageId(), req.getStorageId(), req.getPostCode());
        FbaShipPriceRes sizePriceRes = new FbaShipPriceRes();
        for (FbaOrderOutputPackageAddReq packageAddReq : req.getPackageAddReqList()) {
            double size = packageAddReq.getHeight() + packageAddReq.getWidth() + packageAddReq.getLength();
            double volume = packageAddReq.getHeight() * packageAddReq.getWidth() * packageAddReq.getLength() / 1000000;
            double weight = packageAddReq.getWeight();

            maxSize = Math.max(size, maxSize);
            maxWeight = Math.max(weight, maxWeight);
            //根据三边和计算
            sizePriceRes = getShipPriceWithReason(
                    null,
                    size,
                    weight,
                    1,
                    req.getStorageId(),
                    businessItemDo.getId(),
                    fbaStorageId,
                    companyDo.getShipPriceVersion()
            );
            if (sizePriceRes.getPriceDo() != null) {
                totalPriceBySize += sizePriceRes.getPriceDo().getPrice() * packageAddReq.getPackageCount();
            } else {
                sizeFlag = true;
                break;
            }
        }

        //根据体积计算  sizeType 2
        FbaShipPriceRes volPriceRes = getShipPriceWithReason(
                req.getPackageAddReqList(),
                totalVolume,
                totalWeight,
                2,
                req.getStorageId(),
                businessItemDo.getId(),
                fbaStorageId,
                companyDo.getShipPriceVersion()
        );
        if (volPriceRes.getPriceDo() != null) {
            totalPriceByVolume = volPriceRes.getPriceDo().getPrice();
        } else {
            volumeFlag = true;
        }

        int packageCounts = req.getPackageAddReqList().stream().mapToInt(FbaOrderOutputPackageAddReq::getPackageCount).sum();

        //加急快递（一件代发 佐川即便）
        if (index == 0) {
            List<DicItemRes> dicItemList = dicBusinessItemService.getDicItemList(DicBusinessConstant.trackCompany);
            dicItemList.add(new DicItemRes(DicBusinessItemConstant.fbaTrackNameYHC, dicBusinessItemDao.selectById(DicBusinessItemConstant.fbaTrackNameYHC).getDicItemValue()));
            DicItemRes cheapRes = null;
            double cheapPrice = 0;
            track:
            for (DicItemRes dicItemRes : dicItemList) {
                if (req.getStorageId().intValue() == 15) {
                    if (!(dicItemRes.getId().equals(StaticDict.Track_Type.SagawaExpress.getValue())
                            || dicItemRes.getId().equals(StaticDict.Track_Type.YamatoExpressBig.getValue()))) {
                        continue track;
                    }
                } else {
                    if (!(dicItemRes.getId().equals(StaticDict.Track_Type.SagawaExpress.getValue())
                            || dicItemRes.getId().equals(StaticDict.Track_Type.YamatoExpress.getValue()))) {
                        continue track;
                    }
                }
                double totalPriceBySizeSagawa = 0;
                for (FbaOrderOutputPackageAddReq packageAddReq : req.getPackageAddReqList()) {
                    double[] packageSize = mShipPriceService.getSizeOrderDesc(packageAddReq.getLength(), packageAddReq.getWidth(), packageAddReq.getHeight());
                    double[] sizeRes = new double[8];
                    sizeRes[0] = packageSize[0];
                    sizeRes[1] = packageSize[1];
                    sizeRes[2] = packageSize[2];
                    sizeRes[3] = packageAddReq.getWeight();
                    ShipPriceDo shipPrices;
                    if (req.getFbaStorageId() == null) {
                        shipPrices = mShipPriceService.queryByRegionAndSize(
                                regionService.getStateIdByPostCode(req.getPostCode()),
                                sizeRes, 0, 0, req.getStorageId(), dicItemRes.getId(), 1, 1, companyId);
                    } else {
                        shipPrices = mShipPriceService.queryByRegionAndSize(
                                regionService.getStateIdByRegionId(fbaStorageDao.selectById(fbaStorageId).getReginJpId()),
                                sizeRes, 0, 0, req.getStorageId(), dicItemRes.getId(), 1, 1, companyId);
                    }

                    if (shipPrices == null) {
                        //未找到费用信息，请人工处理
//                        sizeFlag = true;
                        continue track;
                    } else {
                        totalPriceBySizeSagawa += shipPrices.getPrice() * packageAddReq.getPackageCount();
                    }
                }
                if (cheapRes == null || cheapPrice > totalPriceBySizeSagawa) {
                    cheapRes = dicItemRes;
                    cheapPrice = totalPriceBySizeSagawa;
                }
            }
            if (cheapRes != null) {
                //先根据 version 1 获取最便宜的 物流方式，在根据物流方式和公司物流版本号 获取价格
                cheapPrice = 0;
                for (FbaOrderOutputPackageAddReq packageAddReq : req.getPackageAddReqList()) {
                    double[] packageSize = mShipPriceService.getSizeOrderDesc(packageAddReq.getLength(), packageAddReq.getWidth(), packageAddReq.getHeight());
                    double[] sizeRes = new double[8];
                    sizeRes[0] = packageSize[0];
                    sizeRes[1] = packageSize[1];
                    sizeRes[2] = packageSize[2];
                    sizeRes[3] = packageAddReq.getWeight();
                    ShipPriceDo shipPrices = mShipPriceService.queryByRegionAndSize(
                            regionService.getStateIdByRegionId(fbaStorageDao.selectById(fbaStorageId).getReginJpId()),
                            sizeRes, req.getStorageId(), cheapRes.getId(), companyDo.getShipPriceVersion(), companyId);
                    if (shipPrices == null) {
                        //未找到费用信息，请人工处理
//                        sizeFlag = true;
                        cheapRes = null;
                        break;
                    } else {
                        cheapPrice += shipPrices.getPrice() * packageAddReq.getPackageCount();
                    }
                }
                if (cheapRes != null) {
                    Map<String, Object> sagawaMap = new HashMap<>();
                    sagawaMap.put("shipFee", cheapPrice);
                    sagawaMap.put("operateFee", packageCounts * 100 + 200);
                    sagawaMap.put("trackId", cheapRes.getId());
                    sagawaMap.put("trackName", StaticDict.Track_Type.getText(cheapRes.getParentId()));
                    sagawaMap.put("type", StringsUtil.createI18Message("次日发出"));
                    sagawaMap.put("size", maxSize + "cm / 260cm");
                    sagawaMap.put("flag", true); //如果是true 则可以选择
                    priceList.add(sagawaMap);
                }
            } else {
                Map<String, Object> sagawaMap = new HashMap<>();
                sagawaMap.put("trackId", DicBusinessItemConstant.sagawaExpress);
                sagawaMap.put("trackName", StaticDict.Track_Type.getText(DicBusinessItemConstant.sagawaExpress));
                sagawaMap.put("type", StringsUtil.createI18Message("包裹最大尺寸") + "：" + maxSize + "cm " + StringsUtil.createI18Message("超过支持的最大尺寸") + "(260cm)");
                sagawaMap.put("size", maxSize + "cm / 260cm");
                sagawaMap.put("flag", false); //如果是true 则可以选择
                priceList.add(sagawaMap);
            }
        }
        //根据尺寸计算得出结果
        if (!sizeFlag) {
            Map sizeMap = new HashMap();
            sizeMap.put("shipFee", totalPriceBySize);
            sizeMap.put("operateFee", packageCounts * 100 + 200);
            sizeMap.put("trackId", businessItemDo.getId());
            sizeMap.put("trackName", StringsUtil.createI18Message(businessItemDo.getDicItemValue()));
            if (req.getFbaStorageId() == null || req.getFbaStorageId() == 34 || req.getFbaStorageId() == 35 ||
                    (req.getFbaStorageId() >= 80 && req.getFbaStorageId() <= 86)) {
                sizeMap.put("type", StringsUtil.createI18Message("不支持乐天和私人地址"));
                sizeMap.put("flag", false); //如果是true 则可以选择
            } else {
                sizeMap.put("type", StringsUtil.createI18Message("次日发出，发出后3日内到达"));
                sizeMap.put("flag", true); //如果是true 则可以选择

            }
            sizeMap.put("size", maxSize + "cm / " + sizePriceRes.getSizeOrVol() + "cm");
            priceList.add(sizeMap);
        }
        //根据体积计算得出结果
        else if (!volumeFlag) {
            Map<String, Object> volumeMap = new HashMap<>();
            volumeMap.put("shipFee", totalPriceByVolume);
            volumeMap.put(
                    "operateFee",
                    BigDecimal.valueOf(totalVolume)
                            .multiply(BigDecimal.valueOf(280))
                            .setScale(2, RoundingMode.HALF_UP)
                            .doubleValue()
                            + volPriceRes.getOperateFee()
            );
            volumeMap.put("trackId", businessItemDo.getId());
            volumeMap.put("trackName", StringsUtil.createI18Message(businessItemDo.getDicItemValue()));
            if (businessItemDo.getId().equals(DicBusinessItemConstant.fbaTrackNameXinong)) {
                volumeMap.put("type", StringsUtil.createI18Message("3日内发出"));
                volumeMap.put("size", numberfromat(totalVolume) + "m³ /" + numberfromat(volPriceRes.getSizeOrVol()) + " m³");
                volumeMap.put("flag", true);
            } else if (req.getFbaStorageId() != null && req.getFbaStorageId() == 39 && businessItemDo.getId().equals(DicBusinessItemConstant.fbaTrackName10t)) {
                volumeMap.put("flag", totalVolume <= 26);
                volumeMap.put("size", numberfromat(totalVolume) + "m³ /" + " 26m³");
                volumeMap.put("type", "该仓库托盘限高1.6m，装载最大体积为26m³");
            } else if (businessItemDo.getId().equals(DicBusinessItemConstant.fbaTrackName2t)
                    && req.getFbaStorageId() != null && ((req.getFbaStorageId() >= 16 && req.getFbaStorageId() <= 19) || req.getFbaStorageId() == 33
                    || req.getFbaStorageId() == 42 || req.getFbaStorageId() == 70 || req.getFbaStorageId() == 14)) {
                volumeMap.put("type", StringsUtil.createI18Message("无法派送"));
                volumeMap.put("flag", false);
            } else {
                volumeMap.put("size", numberfromat(totalVolume) + "m³ /" + numberfromat(volPriceRes.getSizeOrVol() - 2) + " m³");
//                volumeMap.put("type", String.format("预计%s号送达(节假日顺延)", TimeUtils.getddDate(4)));
                volumeMap.put("type", StringsUtil.createI18Message("except.day.send", TimeUtils.getddDate(4)));

                volumeMap.put("flag", true);
            }
            priceList.add(volumeMap);
        } else if (StringUtils.isNotBlank(sizePriceRes.getReason()) || StringUtils.isNotBlank(volPriceRes.getReason())) {
            //不满足条件
            Map<String, Object> volumeMap = new HashMap<>();
            volumeMap.put("trackId", businessItemDo.getId());
            volumeMap.put("trackName", StringsUtil.createI18Message(businessItemDo.getDicItemValue()));

            volumeMap.put("type", StringUtils.isNotBlank(volPriceRes.getReason()) ? volPriceRes.getReason() : sizePriceRes.getReason());
            if (StringUtils.isNotBlank(volPriceRes.getReason())) {//体积或重量
                if ("weightReason".equals(volPriceRes.getType())) {
                    //重量原因
                    volumeMap.put("size", numberfromat(maxWeight) + "kg /" + numberfromat(volPriceRes.getSizeOrVol()) + " kg");
                } else {
                    volumeMap.put("size", numberfromat(totalVolume) + "m³ /" + numberfromat(volPriceRes.getSizeOrVol()) + " m³");
                }
            } else {
                if ("weightReason".equals(sizePriceRes.getType())) {//三遍和或重量
                    //重量原因
                    volumeMap.put("size", numberfromat(maxWeight) + "kg /" + numberfromat(sizePriceRes.getSizeOrVol()) + " kg");
                } else {
                    volumeMap.put("size", maxSize + "cm / " + sizePriceRes.getSizeOrVol() + "cm");
                }
            }
            volumeMap.put("flag", false);
            priceList.add(volumeMap);
        }

    }


    private double numberfromat(double totalVolume) {
        return new BigDecimal(totalVolume).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }


    private double getVolumeAndWeight(double volume, double weight) {
        double volumeAndWeight = volume * 300 - weight > 0 ? volume * 300 : weight;
        for (int j : sizeArr) {
            if (volumeAndWeight < j) {
                return j;
            }
        }
        return volumeAndWeight;
    }


    private void handlerFbaStorageAdd(FbaOrderOutputDo entityDo, Long fileId, Long productFileId, Long trackId, List<FbaOrderOutputPackageAddReq> packageList, Long userId) {
        int packageCount = 0, productCount = 0;
        int currentPackage = 0;
        if (!CollectionUtils.isEmpty(packageList)) {
            StringBuilder sb = new StringBuilder();
            StringBuilder storageSku = new StringBuilder();
            for (FbaOrderOutputPackageAddReq packageAddReq : packageList) {
                if (packageAddReq.getPoNumber() != null && !sb.toString().contains(packageAddReq.getPoNumber())) {
                    if (sb.length() > 0) {
                        sb.append(",");
                    }
                    sb.append(packageAddReq.getPoNumber());
                }
                currentPackage = currentPackage + 1;
                if (packageAddReq.getPackageCount() < 1) {
                    throw new BizExceptionI18("pls.input.package.count");
                }
                if (StringUtils.isBlank(packageAddReq.getPoNumber()) && entityDo.getStorageType().equals(SysConstant.FBA_ADDRESS) &&
                        (DicBusinessItemConstant.fbaTrackName2t.equals(trackId)
                                || DicBusinessItemConstant.fbaTrackName4t.equals(trackId)
                                || DicBusinessItemConstant.fbaTrackName10t.equals(trackId))) {
                    throw new BizExceptionI18("trunk.pls.must.suppler.po");
                }
                FbaOrderOutputPackageDo packageDo = new FbaOrderOutputPackageDo();
                BeanUtils.copyProperties(packageAddReq, packageDo);
                packageDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
                packageDo.setCreateBy(userId);
                packageDo.setCreateTime(new Date());
                packageDo.setFbaOrderOutputId(entityDo.getId());
                if (packageAddReq.getHeight() <= 0) {
                    throw new BizExceptionI18("pls.input.height.g0");
                }
                packageDo.setHeight(packageAddReq.getHeight());
                if (packageAddReq.getLength() <= 0) {
                    throw new BizExceptionI18("pls.input.length.g0");
                }
                packageDo.setLength(packageAddReq.getLength());
                if (packageAddReq.getWeight() <= 0) {
                    throw new BizExceptionI18("pls.input.weight.g0");
                }
                packageDo.setWeight(packageAddReq.getWeight());
                if (packageAddReq.getWidth() <= 0) {
                    throw new BizExceptionI18("pls.input.width.g0");
                }
                packageDo.setWidth(packageAddReq.getWidth());
                if (packageAddReq.getPackageCount() < 0) {
                    throw new BizExceptionI18("pls.input.count.g0");
                }
                packageDo.setCount(packageAddReq.getPackageCount());
                packageDo.setHeight(packageAddReq.getHeight());
                packageDo.setLength(packageAddReq.getLength());
                packageDo.setWeight(packageAddReq.getWeight());
                packageDo.setWidth(packageAddReq.getWidth());
                packageDo.setCount(packageAddReq.getPackageCount());
                packageDao.insert(packageDo);
                packageCount += packageAddReq.getPackageCount();
                if (StringUtils.isNotBlank(packageAddReq.getPoNumber())) {
                    if (!storageSku.toString().contains(packageAddReq.getPoNumber())) {
                        if (storageSku.length() > 0) {
                            storageSku.append(",");
                        }
                        storageSku.append(packageAddReq.getPoNumber());
                    }
                }
                if (!CollectionUtils.isEmpty(packageAddReq.getProductList())) {
//                    if (StringUtils.isBlank(packageAddReq.getUpcNumber()))
//                        throw new BizException("请输入SKU对照关系(FNSKU或UPC)");
                    for (FbaOrderOutputProductAddReq productAddReq : packageAddReq.getProductList()) {
                        FbaOrderOutputProductDo outputProductDo = new FbaOrderOutputProductDo();
                        if (productAddReq.getCount() < 0) {
                            throw new BizExceptionI18("input.product.count.g0");
                        }
                        outputProductDo.setCount(productAddReq.getCount());
                        outputProductDo.setCreateTime(new Date());
                        outputProductDo.setCreateBy(userId);
                        outputProductDo.setOrderId(entityDo.getId());
                        outputProductDo.setPackageId(packageDo.getId());
                        outputProductDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
                        if (productAddReq.getProductId() == null) {
                            productAddReq.setProductId(getProductId(productAddReq.getCommoditySku(), entityDo.getCompanyId()));
                        }
                        if (productAddReq.getProductId() == null) {
                            throw new BizExceptionI18("no.product.info");
                        }

                        outputProductDo.setProductId(productAddReq.getProductId());
                        ProductInfoDo productInfoDo = productInfoDao.selectById(productAddReq.getProductId());
                        if (productInfoDo == null) {
                            throw new BizException(SysConstant.Product_NotExist);
                        }
                        if (storageSku.length() > 0) {
                            storageSku.append(",");
                        }
                        storageSku.append(productInfoDo.getStorageSku());
                        if (packageAddReq.getProductList().size() == 1 && productAddReq.getCount() == 1) {
                            if (packageAddReq.getLength() * packageAddReq.getWidth() * packageAddReq.getHeight() <
                                    productInfoDo.getLength() * productInfoDo.getWidth() * productInfoDo.getHeight() * productAddReq.getCount() * 0.8) {
                                throw new BizExceptionI18("package.and.product.size.over.difference", currentPackage);
                            }
                        }
                        verifyStock(entityDo.getShopId(), entityDo.getStorageId(), productAddReq.getProductId(),
                                productAddReq.getCount() * packageAddReq.getPackageCount(),
                                productInfoDo.getCommoditySku());

                        productDao.insert(outputProductDo);
                        productCount += packageAddReq.getPackageCount() * productAddReq.getCount();
                    }
                }
            }
            int packageFee = 0;
            int productFee = 0;
            if (fileId != null) {
                packageFee = 100 * packageCount;
            }
            if (productFileId != null) {
                productFee = 80 * packageCount;
            }
            entityDo.setPoNumber(sb.toString());
            entityDo.setOperateFee(packageFee + productFee);
            entityDo.setStorageSku(storageSku.toString());
        }
    }


    private void sufficientFundsCheck(Long companyId) {
        if (!companyAccountService.getIsDue(companyId) || companyId.intValue() == 44) {
            throw new NotSufficientFundsException(ErrorEnum.NOT_SUFFICIENT_FUNDS);
        }
    }

//     private String handlerAddProduct(List<OrderOutputProductAddReq> orderProductList, FbaOrderOutputDo entityDo, Long userId) {
//         FbaOrderOutputPackageDo packageDo = new FbaOrderOutputPackageDo();
//         packageDo.setCreateBy(userId);
//         packageDo.setFbaOrderOutputId(entityDo.getId());
//         packageDo.setCreateTime(new Date());
//         packageDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
//         packageDao.insert(packageDo);
//         for (OrderOutputProductAddReq productReq : orderProductList) {
//             if (productReq.getProductId() == 0)
//                 return ("没有该产品信息" + productReq.getCommoditySku());
//             ProductInfoDo productInfoDo = productInfoDao.selectById(productReq.getProductId());
//             if (productInfoDo == null)
//                 return ("没有该产品信息" + productReq.getCommoditySku());
//             FbaOrderOutputProductDo outputProductDo = new FbaOrderOutputProductDo();
//             outputProductDo.setProductId(productReq.getProductId());
//             outputProductDo.setCount(productReq.getCount());
//             outputProductDo.setPackageId(packageDo.getId());
//             outputProductDo.setOrderId(packageDo.getFbaOrderOutputId());
//             outputProductDo.setCreateBy(userId);
//             outputProductDo.setCreateTime(new Date());
//             outputProductDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
//             String productSku = "";
//             ProductInfoDo productInfo = productInfoDao.selectById(outputProductDo.getProductId());
//             if (productInfo != null) {
//                 productSku = productInfoDo.getCommoditySku();
//             }
//             LambdaQueryWrapper<StockRecordDo> wrapper = new LambdaQueryWrapper();
// //            sendOutEntity.getCommoditySku(), sendOutEntity.getShopId(), sendOutEntity.getStorageId()
//             wrapper.eq(StockRecordDo::getShopId, entityDo.getShopId()).eq(StockRecordDo::getStorageId, entityDo.getStorageId())
//                     .eq(StockRecordDo::getProductInfoId, outputProductDo.getProductId());
//             StockRecordDo recordBean = mStockRecordDao.selectOne(wrapper);
//             int count = stockRecordService.getStockCount(rakutenDo.getCompanyId(), rakutenDo.getShopId(), storageDo.getId(), productId, products.get(productId));
//             int waitCount = mStockRecordDao.getOrderOutCount(outputProductDo.getProductId(), entityDo.getShopId(), entityDo.getStorageId());
//             if (recordBean == null || recordBean.getCanSellCount() < 1 ||
//                     recordBean.getCanSellCount() - waitCount < outputProductDo.getCount()) {
//                 //查一遍对应的子SKU
//                 Long productId = getSubProductId(productSku, entityDo.getCompanyId());
//                 wrapper.eq(StockRecordDo::getProductInfoId, productId);
//                 recordBean = mStockRecordDao.selectOne(wrapper);
//                 if (recordBean == null || recordBean.getCanSellCount() < 1 ||
//                         recordBean.getCanSellCount() - waitCount < outputProductDo.getCount()) {
//                     packageDao.deleteById(productId);
//                     productDao.deleteById(packageDo.getId());
//                     dao.deleteById(entityDo.getId());
//                     return productSku + SysConstant.ERROR_MSG_NO_STOCK;
//                 }
//             }
//             productDao.insert(outputProductDo);
//
//         }
//         // 产品数量过多时需要人工审核，状态改为-1
//         if (orderProductList.size() > SysConstant.OUTPUT_PRODUCT_SIZE_LIMIT) {
//             entityDo.setStatus(DicBusinessItemConstant.fbaInCreateState);
//             updateById(entityDo);
//         }
//         return null;
//     }

    /**
     * 验证库存
     *
     * @param shopId
     * @param storageId
     * @param productId
     * @param count
     * @param commoditySku
     */
    private void verifyStock(Long shopId, Long storageId, Long productId, int count, String commoditySku) {
        LambdaQueryWrapper<StockRecordDo> wrapper = new LambdaQueryWrapper();
//            sendOutEntity.getCommoditySku(), sendOutEntity.getShopId(), sendOutEntity.getStorageId()
        wrapper.eq(StockRecordDo::getShopId, shopId).eq(StockRecordDo::getStorageId, storageId)
                .eq(StockRecordDo::getProductInfoId, productId);
        StockRecordDo recordBean = mStockRecordDao.selectOne(wrapper);
        if (shopId == null) {
            shopId = 0L;
        }
        int inputCount = orderInputProductDao.selectInputOrderSkuReceiveCount(productId, shopId, storageId, DicBusinessItemConstant.inPutStorage);
        if (inputCount == 0) {
            inputCount = orderInputProductDao.selectInputOrderSkuCount(productId, shopId, storageId, DicBusinessItemConstant.inPutStorage);
        }
        int waitCount = mStockRecordDao.getOrderOutCount(productId, shopId, storageId) +
                mStockRecordDao.getOrderOutTurn2FbaCount(productId, shopId, storageId);
        int canUseCount = 0;
        if (recordBean == null) {
            canUseCount = inputCount - waitCount;
        } else {
            canUseCount = recordBean.getCanSellCount() + inputCount - waitCount;
        }
        if (canUseCount < count) {
            Long product = null;
            try {
                product = getSubProductId(commoditySku, shopDao.selectById(shopId).getCompanyId());
            } catch (Exception e) {
                return;
            }
            wrapper.eq(StockRecordDo::getProductInfoId, product);
            recordBean = mStockRecordDao.selectOne(wrapper);
            if (recordBean == null || recordBean.getCanSellCount() < 1
                    || recordBean.getCanSellCount() - waitCount < count) {
                throw new BizExceptionI18("product.stock.notEnough", commoditySku);
            }
        }
    }

    //新增校验
    private String addCheck(FbaOrderOutputAddReq req) {
//        if (!StringUtils.isNotBlank(req.getPostCode()))
//            throw new BizException("缺少邮编");
//        if (!StringUtils.isNotBlank(req.getAddress()))
//            throw new BizException("缺少收货地址");
        if (req.getShopId() == null) {
            throw new BizExceptionI18("order.no.shop");
        }
        if (req.getStorageId() == null) {
            throw new BizExceptionI18("order.no.storage");
        }
        if (req.getPackageList() == null ||
                req.getPackageList().size() < 1) {
            throw new BizExceptionI18("order.no.product");
        }
        if (req.getFbaStorageId() == null && req.getStorageType() != null && "fba".equals(req.getStorageType())) {
            throw new BizExceptionI18("pls.choose.fba.storage");
        }
        if (req.getTrackId() == null) {
            throw new BizExceptionI18("pls.choose.track");
        }
        if (req.getTrackId().equals(DicBusinessItemConstant.fbaTrackNameGreenBox) &&
                (req.getFbaStorageId() == null || req.getFbaStorageId() == 34 || req.getFbaStorageId() == 35 ||
                        (req.getFbaStorageId() >= 80 && req.getFbaStorageId() <= 86))) {
            throw new BizExceptionI18("no.support.feiyun.letian");
        }
        if (req.getTrackId().equals(DicBusinessItemConstant.fbaTrackName2t) && req.getFbaStorageId() != null &&
                ((req.getFbaStorageId() >= 16 && req.getFbaStorageId() <= 19) || req.getFbaStorageId() == 33 || req.getFbaStorageId() == 14
                        || req.getFbaStorageId() == 42 || req.getFbaStorageId() == 70)) {
            throw new BizExceptionI18("no.support.2t.fbaStorage.list");
        }
        return null;
    }


    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(FbaOrderOutputDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        entityDo.setSendDate(new Date());
        entityDo.setStatus(DicBusinessItemConstant.fbaInCreateState);
        entityDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
    }

    //将新增的do转换成要返回的实体
    private String handlerAddAfter(FbaOrderOutputDo entityDo, OrderOutputAddReq req) {
        entityDo.setFbaOrderOutputNumber(OrderCodeUtil.getOrderOutNumber(entityDo.getId()));

        updateTrackId(entityDo);
        return null;
    }

    @Override
    public SingleResult updateInit(Long id, Long companyId) {
        FbaOrderOutputDo outputDo = dao.selectById(id);
        if (outputDo.getStatus() > DicBusinessItemConstant.fbaOrderBackCheckStatus) {
            throw new BizExceptionI18("order.hadDeal");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("storage", storageService.getJpList());
        map.put("region", regionService.getList(new HashMap<>()));
        LambdaQueryWrapper<ProductInfoDo> productInfoWrapper = new LambdaQueryWrapper<>();
        productInfoWrapper.eq(ProductInfoDo::getCompanyId, outputDo.getCompanyId());
        List<ProductInfoDo> productInfoDoList = productInfoDao.selectList(productInfoWrapper);
        List<IdAndNameEntity> productSkuList = new ArrayList<>();
        for (ProductInfoDo productInfoDo : productInfoDoList) {
            productSkuList.add(new IdAndNameEntity(productInfoDo.getId().intValue(), productInfoDo.getCommoditySku()));
        }
        map.put("productSku", productSkuList);
        FbaOrderOutputDetailRes detailRes = detail(id, true);

        //fbaStorage
        QueryWrapper wrapper1 = new QueryWrapper();
        wrapper1.orderByAsc("fba_code");
        List<FbaStorageDo> fbaStorageDos = fbaStorageDao.selectList(wrapper1);
        List<Map> fbaStorageList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(fbaStorageDos)) {
            fbaStorageDos.forEach(fbaStorageDo -> {
                Map fbaMap = new HashMap();
                fbaMap.put("id", fbaStorageDo.getId());
                fbaMap.put("code", fbaStorageDo.getFbaCode());
                fbaMap.put("name", fbaStorageDo.getFbaName());
                fbaMap.put("address", fbaStorageDo.getAddress());
                fbaMap.put("postCode", fbaStorageDo.getPostCode());
                fbaMap.put("tel", fbaStorageDo.getTelPhone());
                fbaStorageList.add(fbaMap);
            });
        }
        map.put("fbaStorageList", fbaStorageList);

        List<ShippingAddressDo> addressList = shippingAddressDao.selectList(new QueryWrapper<ShippingAddressDo>().eq("company_id", companyId));
        List<Map> resList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(addressList)) {
            addressList.forEach(addressDo -> {
                Map map1 = new HashMap();
                map1.put("id", addressDo.getId());
                map1.put("name", addressDo.getContact());
                map1.put("companyName", addressDo.getCompanyName());
                map1.put("address", addressDo.getAddress());
                map1.put("postCode", addressDo.getPostCode());
                map1.put("tel", addressDo.getTelPhone());
                resList.add(map1);
            });
        }
        map.put("ownAddressList", resList);

        map.put("detail", detailRes);
        return SingleResult.success(map);
    }

    @Override
    public FbaOrderOutputUpdateReq update(FbaOrderOutputUpdateReq req, Long userId) {
        updateCheck(req);
        FbaOrderOutputDo entityDo = dao.selectById(req.getId());
        if (entityDo == null) {
            throw new BizExceptionI18("pls.retry.no.order");
        }
        if (req.getFileId() == null) {
            fileService.deleteFile(entityDo.getFileId());
        } else if (!req.getFileId().equals(entityDo.getFileId())) {
            fileService.uploadFile2(req.getFileId(), entityDo.getFileId());
        }
        if (req.getProductFileId() == null) {
            fileService.deleteFile(entityDo.getProductFileId());
        } else if (!req.getProductFileId().equals(entityDo.getProductFileId())) {
            fileService.uploadFile2(req.getProductFileId(), entityDo.getProductFileId());
        }
        if (req.getOtherFileId() == null) {
            fileService.deleteFile(entityDo.getOtherFileId());
        } else if (!req.getOtherFileId().equals(entityDo.getOtherFileId())) {
            fileService.uploadFile2(req.getOtherFileId(), entityDo.getOtherFileId());
        }

        if (entityDo.getStatus() >= DicBusinessItemConstant.fbaOrderBackCheckStatus &&
                !DicBusinessItemConstant.fbaOrderProblemStatus.equals(entityDo.getStatus())) {
            throw new BizExceptionI18("order.operated");
        }
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setTrackId(req.getTrackId());
        handlerUpdateBefore(entityDo, userId);


        //日志操作
        operateRecordService.operateAddRecord(SysConstant.OPERATE_UPDATE_FBA_ORDER, entityDo.getId(), userId, 6);
//        operateRecord("修改", entityDo.getId(), userId);
        entityDo.setDeliveryTime(req.getDeliveryTime());
        if (StringUtils.isNotBlank(req.getDeliveryDate())) {
            entityDo.setDeliveryDate(TimeUtils.parseDate(req.getDeliveryDate()));
        } else {
            entityDo.setDeliveryDate(null);
        }
        handlerFee(entityDo);
        return handlerUpdateAfter(req, entityDo);
    }

    private void handlerFee(FbaOrderOutputDo entityDo) {
        LambdaQueryWrapper<FbaOrderOutputPackageDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, entityDo.getId());
        List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(wrapper);
        int[] productCounts = new int[1];//如果是按三边和计算，每个商品200,统计所有商品的总数量
        double totalPriceBySize = 0;
        double totalPriceBySizeSagawa = 0;
        double totalPriceByVolume = 0;
        //计算总体积 总尺寸
        double totalSize = 0;
        double totalVolume = 0;
//        double totalVolumeAndWeight = 0;
        double totalWeight = 0;
        //如果flag为true表示 有的包裹价格匹配不上，则 不展示该快递公司的 运算价格
        boolean sizeFlag = false;
        boolean volumeFlag = false;
        CompanyDo companyDo = companyDao.selectById(entityDo.getCompanyId());
        Long fbaStorageId = getFbaStorageId(entityDo.getFbaStorageId(), entityDo.getStorageId(), entityDo.getPostCode());
        for (FbaOrderOutputPackageDo packageDo : packageDoList) {
            double size = packageDo.getHeight() + packageDo.getWidth() + packageDo.getLength();
            double[] packageSize = mShipPriceService.getSizeOrderDesc(packageDo.getLength(), packageDo.getWidth(), packageDo.getHeight());

            double volume = packageDo.getHeight() * packageDo.getWidth() * packageDo.getLength() / 1000000;
            double weight = packageDo.getWeight();

            totalSize += size;
            totalVolume += volume * packageDo.getCount();
            totalWeight += weight * packageDo.getCount();
            //根据三边和计算  sizeType 1
            FbaShipPriceDo shipPriceDo = getShipPrice(
                    size,
                    weight,
                    1,
                    entityDo.getStorageId(),
                    entityDo.getTrackId(),
                    fbaStorageId,
                    companyDo.getShipPriceVersion()
            );
            if (shipPriceDo != null) {
                totalPriceBySize += shipPriceDo.getPrice() * packageDo.getCount();
            } else {
                sizeFlag = true;
            }
            double[] sizeRes = new double[8];
            sizeRes[0] = packageSize[0];
            sizeRes[1] = packageSize[1];
            sizeRes[2] = packageSize[2];
            sizeRes[3] = packageDo.getWeight();
            ShipPriceDo shipPrices = mShipPriceService.queryByRegionAndSize(
                    regionService.getStateIdByRegionId(fbaStorageDao.selectById(fbaStorageId).getReginJpId()),
                    sizeRes, entityDo.getStorageId(), DicBusinessItemConstant.sagawaExpress, companyDo.getShipPriceVersion(), companyDo.getId());
            if (shipPrices == null) {
                //未找到费用信息，请人工处理
                sizeFlag = true;
            } else {
                totalPriceBySizeSagawa += shipPrices.getPrice() * packageDo.getCount();
            }
        }

        int packageCounts = packageDoList.stream().mapToInt(FbaOrderOutputPackageDo::getCount).sum();
        packageDoList.stream().forEach(fbaOrderOutputPackageDo -> {
            //统计商品数量计算操作费
            LambdaQueryWrapper<FbaOrderOutputProductDo> productDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            productDoLambdaQueryWrapper.eq(FbaOrderOutputProductDo::getPackageId, fbaOrderOutputPackageDo.getId());
            List<FbaOrderOutputProductDo> orderOutputProductDoList = productDao.selectList(productDoLambdaQueryWrapper);
            if (!CollectionUtils.isEmpty(orderOutputProductDoList)) {
                productCounts[0] += orderOutputProductDoList.stream().mapToInt(FbaOrderOutputProductDo::getCount).sum() * fbaOrderOutputPackageDo.getCount();
            }
        });
        //根据体积计算  sizeType 2
        FbaShipPriceDo shipPriceDo;
        if (DicBusinessItemConstant.fbaTrackNameXinong.equals(entityDo.getTrackId())) {
            shipPriceDo = getShipPrice(
                    totalVolume,
                    totalWeight,
                    2,
                    entityDo.getStorageId(),
                    entityDo.getTrackId(),
                    fbaStorageId,
                    companyDo.getShipPriceVersion()
            );
        } else {
            shipPriceDo = getShipPrice(
                    totalVolume,
                    totalWeight,
                    2,
                    entityDo.getStorageId(),
                    entityDo.getTrackId(),
                    fbaStorageId,
                    companyDo.getShipPriceVersion()
            );
        }
        if (shipPriceDo != null) {
            totalPriceByVolume = shipPriceDo.getPrice();
        } else {
            volumeFlag = true;
        }


        //根据尺寸计算得出结果
        //加急快递
        if (DicBusinessItemConstant.sagawaExpress.equals(entityDo.getTrackId())) {
            entityDo.setShipFee(totalPriceBySizeSagawa);
            entityDo.setOutFee(packageCounts * 200 * 0.5);
        }//根据尺寸计算得出结果
        if (DicBusinessItemConstant.fbaTrackNameGreenBox.equals(entityDo.getTrackId())) {
            entityDo.setShipFee(totalPriceBySize);
            entityDo.setOutFee(packageCounts * 200 * 0.5);
        } else if (totalPriceByVolume != 0) {//根据体积计算得出结果
            entityDo.setShipFee(totalPriceByVolume);
            entityDo.setOutFee(280 * totalVolume);
        }
        if (SysConstant.DELETE_FLAG_FALSE.equals(entityDo.getIsSetFee())) {
            entityDo.setOperateFee(getPackageLabelFee(packageCounts, companyDo));
            if (entityDo.getProductFileId() != null) {
                entityDo.setOperateFee(entityDo.getOperateFee() + getProductLabelFee(productCounts[0], companyDo, entityDo));
            }
        }

        //计算taxFee
        double taxFee = (entityDo.getOperateFee() + entityDo.getShipFee() + entityDo.getOutFee()) * 0.1;
        entityDo.setTaxFee(taxFee);

        entityDo.setTrackId(entityDo.getTrackId());
//        dao.updateById(entityDo);
    }

    private double getPackageLabelFee(int packageCounts, CompanyDo companyDo) {
        //普价客户且数量大于100时按80算
        if (packageCounts >= 100 && companyDo.getPackageLabel().intValue() == 100) {
            return packageCounts * 80;
        } else {
            return packageCounts * companyDo.getPackageLabel();
        }
    }

    private double getProductLabelFee(int productCounts, CompanyDo companyDo, FbaOrderOutputDo entityDo) {
        //普价客户且数量大于500时按60算
        if (productCounts >= 500 && companyDo.getProductLabel().intValue() == 80) {
            return productCounts * 60;
        } else if (productCounts > 0) {
            return productCounts * companyDo.getProductLabel();
        } else {
            entityDo.setTips(entityDo.getTips() + "sys:无产品数量,按100个计算");
            return 100 * companyDo.getProductLabel();
        }
    }

    private Long getFbaStorageId(Long fbaOrigionId, Long storageId, String postCode) {
        Long fbaStorageId = 0L;
        if (fbaOrigionId == null || fbaOrigionId == 86L) {
            LambdaQueryWrapper<FbaStorageDo> fbaStorageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            JpRegionDo regionDo = regionService.getRegionDoByPostCode(postCode);
            Long regionId = 9L;
            Long stateId = 0L;
            if (regionDo == null) {
                if (storageId == 13 || storageId == 15 || storageId == 11) {
                    regionId = 14L;
                    stateId = 5L;
                } else {
                    stateId = 9L;
                    regionId = 27L;
                }
            } else {
                regionId = regionDo.getId();
                stateId = regionDo.getJpStateId();
            }
            fbaStorageDoLambdaQueryWrapper.eq(FbaStorageDo::getReginJpId, regionId)
                    .le(FbaStorageDo::getId, 26)
                    .orderByDesc(FbaStorageDo::getId)
                    .last("limit 1");
            FbaStorageDo storageDo = fbaStorageDao.selectOne(fbaStorageDoLambdaQueryWrapper);
            if (storageDo == null) {
                List<JpRegionDo> jpRegionDos = regionService.getBaseMapper().selectList(new LambdaQueryWrapper<JpRegionDo>().eq(JpRegionDo::getJpStateId, stateId));
                if (jpRegionDos.size() > 0) {
                    for (JpRegionDo jpRegionDo : jpRegionDos) {
                        fbaStorageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                        fbaStorageDoLambdaQueryWrapper.eq(FbaStorageDo::getReginJpId, jpRegionDo.getId())
                                .le(FbaStorageDo::getId, 26)
                                .orderByDesc(FbaStorageDo::getId)
                                .last("limit 1");
                        FbaStorageDo storageDo1 = fbaStorageDao.selectOne(fbaStorageDoLambdaQueryWrapper);
                        if (storageDo1 != null) {
                            storageDo = storageDo1;
                            break;
                        }
                        ;
                    }
                } else {
//                    do {
//                        fbaStorageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
//                        if (regionId < 0 || regionId > 46) break;
//                        if (storageId == 13 || storageId == 10 || storageId == 11) {
//                            if (regionId < 12) {
//                                regionId = regionId - 1;
//                            } else {
//                                regionId = regionId + 1;
//                            }
//                        } else {
//                            if (regionId < 27) {
//                                regionId = regionId - 1;
//                            } else {
//                                regionId = regionId + 1;
//                            }
//                        }
//                        fbaStorageDoLambdaQueryWrapper.eq(FbaStorageDo::getReginJpId, regionId)
//                                .le(FbaStorageDo::getId, 26)
//                                .orderByDesc(FbaStorageDo::getId)
//                                .last("limit 1");
//                        storageDo = fbaStorageDao.selectOne(fbaStorageDoLambdaQueryWrapper);
//                    } while (storageDo == null);
//                }
//
                }
                if (storageDo == null) {
                    if (storageId == 13 || storageId == 10 || storageId == 11) {
                        fbaStorageId = 26L;
                    } else {
                        fbaStorageId = 26L;
                    }
                } else {
                    fbaStorageId = storageDo.getId();
                }
            } else {
                fbaStorageId = storageDo.getId();
            }
        } else if (fbaOrigionId > 26) {
            LambdaQueryWrapper<FbaStorageDo> fbaStorageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            FbaStorageDo storageDo1 = fbaStorageDao.selectById(fbaOrigionId);
            if (storageDo1 == null) {
                throw new BizExceptionI18("no.fba.storage");
            }
            fbaStorageDoLambdaQueryWrapper.eq(FbaStorageDo::getReginJpId, storageDo1.getReginJpId())
                    .le(FbaStorageDo::getId, 26)
                    .orderByDesc(FbaStorageDo::getId)
                    .last("limit 1");
            FbaStorageDo storageDo = fbaStorageDao.selectOne(fbaStorageDoLambdaQueryWrapper);
            fbaStorageId = storageDo.getId();
        } else {
            fbaStorageId = fbaOrigionId;
        }
        return fbaStorageId;
    }

    private FbaShipPriceRes getShipPriceWithReason(List<FbaOrderOutputPackageAddReq> packageAddReqList, double size, double weight, int sizeType, Long storageId, Long trackId, Long fbaStorageId, int shipPriceVersion) {
        FbaShipPriceRes res = new FbaShipPriceRes();
        //先判断 size type 原因
        FbaDimensDo et = fbaDimensDao.selectOne(
                new LambdaQueryWrapper<FbaDimensDo>()
                        .eq(FbaDimensDo::getType, sizeType)
                        .eq(FbaDimensDo::getStorageId, storageId)
                        .eq(FbaDimensDo::getTrackId, trackId)
                        .orderByDesc(FbaDimensDo::getSize)
                        .last(" limit 1")
        );
        //如果查不到 说明sizeType 值不对 1或 2
        if (et == null) {
            res.setType("sizeTypeReason");
            return res;
        }
        /*//todo 推荐体积
        //所有商品信息
        List<FbaOrderOutputProductAddReq> productAddReqs = new ArrayList<>();
        packageAddReqList.forEach(item -> productAddReqs.addAll(item.getProductList()));
        //查询sku数用来匹配最大容积量
        long skuCount = productAddReqs.stream()
                .map(FbaOrderOutputProductAddReq::getCommoditySku)
                .distinct().count();
        //获取最长边和次长边
        List<Double> sideLength = packageAddReqList.stream()
                .sorted((i1, i2) -> i1.getLength() >= i2.getLength() ? -1 : 1)
                .map(FbaOrderOutputPackageAddReq::getLength)
                .limit(2)
                .collect(Collectors.toList());
        if (sideLength.size() < 2) {
            sideLength.add(packageAddReqList.get(0).getHeight());
        }
        //最大容积量
        double maxVolume = 0;
        //搬运费
        double cartage = 0;
        if (sideLength.get(0).compareTo(110.0) <= 0 && sideLength.get(1).compareTo(80.0) <= 0) {
            //产品sku数量对体积的影响
            if (skuCount <= 5) {
                maxVolume = 35;
            } else if (skuCount <= 10) {
                maxVolume = 33;
            } else if (skuCount <= 15) {
                maxVolume = 31;
            } else {
                maxVolume = 29;
            }
            //产品重量对体积的影响
            if (sizeType == 2) {
                if (weight < 15) {
                    maxVolume = 35;
                } else if (weight < 20) {
                    maxVolume = 33;
                } else if (weight < 30) {
                    maxVolume = 29;
                    //搬运费10000日元
                    cartage = 10000;
                } else {
                    maxVolume = 25;
                    //搬运费10000日元
                    cartage = 10000;
                }
            }
        } else if (sideLength.get(0).compareTo(110.0) > 0 && sideLength.get(1).compareTo(70.0) < 0) {
            maxVolume -= 2;
        }
        if (sideLength.get(0).compareTo(110.0) > 0 && sideLength.get(1).compareTo(70.0) >= 0) {
            maxVolume -= 4;
        }*/

        LambdaQueryWrapper<FbaDimensDo> fbaDimensDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        fbaDimensDoLambdaQueryWrapper.ge(FbaDimensDo::getSize, size)
                .ge(FbaDimensDo::getWeight, weight)
                .eq(FbaDimensDo::getType, sizeType)
                .eq(FbaDimensDo::getStorageId, storageId)
                .eq(FbaDimensDo::getTrackId, trackId)
                .orderByAsc(FbaDimensDo::getSize)
                .last("limit 1");

        FbaDimensDo fbaDimensDo = fbaDimensDao.selectOne(fbaDimensDoLambdaQueryWrapper);
        if (fbaDimensDo != null) {
            LambdaQueryWrapper<FbaShipPriceDo> fbaShipPriceDoLambdaQueryWrapper = new LambdaQueryWrapper<>();

            fbaShipPriceDoLambdaQueryWrapper.eq(FbaShipPriceDo::getDimensId, fbaDimensDo.getId())
                    .eq(FbaShipPriceDo::getFbaStorageId, fbaStorageId)
                    .eq(FbaShipPriceDo::getVersion, shipPriceVersion)
                    .eq(FbaShipPriceDo::getActive, 1);

            FbaShipPriceDo fbaShipPriceDo = fbaShipPriceDao.selectOne(fbaShipPriceDoLambdaQueryWrapper);
            if (fbaShipPriceDo == null) {
                fbaShipPriceDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                fbaShipPriceDoLambdaQueryWrapper.eq(FbaShipPriceDo::getDimensId, fbaDimensDo.getId())
                        .eq(FbaShipPriceDo::getFbaStorageId, fbaStorageId)
                        .eq(FbaShipPriceDo::getVersion, GlobalConstants.SHIP_PRICE_COMMON)
                        .eq(FbaShipPriceDo::getActive, 1);

                fbaShipPriceDo = fbaShipPriceDao.selectOne(fbaShipPriceDoLambdaQueryWrapper);
            }
            /*if (sizeType == 2) {
                //添加搬运费
                res.setOperateFee(cartage);
                //最大容积量
                if (maxVolume > 0) {
                    fbaDimensDo.setSize(maxVolume);
                } else {
                    if (fbaDimensDo.getSize() + maxVolume > 0) {
                        fbaDimensDo.setSize(fbaDimensDo.getSize() + maxVolume);
                    }
                }
            }*/
            res.setPriceDo(fbaShipPriceDo);
            if (fbaShipPriceDo == null) {
                //说明虽然匹配到了 尺寸 但是没有匹配到价格
                res.setType("priceReason");
                res.setReason(StringsUtil.createI18Message("没有匹配到价格"));
            }
            res.setSizeOrVol(fbaDimensDo.getSize());

        } else {
            //说明没有匹配到尺寸
            List<FbaDimensDo> dimensDoList = fbaDimensDao.selectList(new LambdaQueryWrapper<FbaDimensDo>()
                    .ge(FbaDimensDo::getSize, size)
                    .eq(FbaDimensDo::getType, sizeType)
                    .eq(FbaDimensDo::getStorageId, storageId)
                    .eq(FbaDimensDo::getTrackId, trackId)
                    .orderByAsc(FbaDimensDo::getSize));
            if (dimensDoList.size() == 0) {
                //说明 size 或者体积 不匹配
                if (sizeType == 1) {
                    res.setType("sizeReason");
                    //按三遍和
                    res.setReason(StringsUtil.createI18Message("包裹最大尺寸") + "：" + MathUtils.numberFormat(2, size) + "cm " + StringsUtil.createI18Message("超过支持的最大尺寸") + "(" + et.getSize() + "cm)");
                } else {
                    res.setType("volReason");
                    res.setReason(StringsUtil.createI18Message("所有包裹最大体积") + "：" + MathUtils.numberFormat(2, size) + "m³ " + StringsUtil.createI18Message("超过支持的最大体积") + "(" + et.getSize() + "m³)");
                }
                res.setSizeOrVol(et.getSize());
            } else {
                //说明 重量不匹配
                res.setType("weightReason");
                res.setReason(StringsUtil.createI18Message("所有包裹最大重量") + "：" + MathUtils.numberFormat(2, weight) + "kg " + StringsUtil.createI18Message("超过支持的最大重量") + "+(" + et.getWeight() + "kg)");
                res.setSizeOrVol(et.getWeight());
            }
        }
        return res;
    }

    private FbaShipPriceDo getShipPrice(double size, double weight, int sizeType, Long storageId, Long
            trackId, Long fbaStorageId, int shipPriceVersion) {
        return this.getShipPriceWithReason(
                null,
                size,
                weight,
                sizeType,
                storageId,
                trackId,
                fbaStorageId,
                shipPriceVersion
        ).getPriceDo();
    }


//    @Override
//    public void cutoff(Long id, Long userId, Long companyId) {
//        FbaOrderOutputDo entityDo = dao.selectById(id);
//        if (entityDo.getStatus() != null && entityDo.getStatus().equals(DicBusinessItemConstant.orderCutOff)) {
//            throw new BizException("该订单已经截单");
//        }
//        if (entityDo.getStatus() > DicBusinessItemConstant.outDelivered || entityDo.getStatus() <= DicBusinessItemConstant.outCreateCheckState) {
//            throw new BizException("该订单未在发货途中或已签收，无法截单");
//        }
//        entityDo.setStatus(DicBusinessItemConstant.orderCutOff);
//
//        //日志操作
//        operateRecord("截单", entityDo.getId(), userId);
//
//        dao.updateById(entityDo);
//        threadPoolTaskExecutor.execute(() -> {
//            mailSenderService.sendEmail("有新的截单申请", "单号：" + entityDo.getFbaOrderOutputNumber() + "，请及时处理",
//                    SysConstant.cloudkintEmail);
//        });
//        //将该订单信息添加到退货表中
//        handlerOrderBack(entityDo, userId, companyId);
//    }

    @Override
    public SingleResult salesReturnInit(Long id) {
        List<JSONObject> list = new ArrayList<>();
        LambdaQueryWrapper<FbaOrderOutputProductDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputProductDo::getOrderId, id);
        List<FbaOrderOutputProductDo> orderOutputProductDoList = productDao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(orderOutputProductDoList)) {
            orderOutputProductDoList.forEach(orderOutputProductDo -> {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("productId", orderOutputProductDo.getProductId());
                jsonObject.put("count", orderOutputProductDo.getCount());
                ProductInfoDo productInfoDo = productInfoDao.selectById(orderOutputProductDo.getProductId());
                if (productInfoDo != null) {
                    jsonObject.put("productName", productInfoDo.getProductName());
                    jsonObject.put("sku", productInfoDo.getCommoditySku());
                }
                list.add(jsonObject);
            });
        }

        return SingleResult.success(list);
    }

//    @Override
//    public void salesReturn(FbaOrderOutputSalesReturnReq req, Long userId, Long companyId) {
//        FbaOrderOutputDo orderOutputDo = dao.selectById(req.getId());
//
//        if (orderOutputDo.getStatus() < DicBusinessItemConstant.fbaOrderSendOutStatus || orderOutputDo.getStatus() >= DicBusinessItemConstant.outHasRecovered) {
//            throw new BizException("该订单尚未发货或已经追回，无法发货");
//        }
//
//        LambdaQueryWrapper<OrderBackDo> orderBackDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        orderBackDoLambdaQueryWrapper.eq(OrderBackDo::getOrderOutNumber, orderOutputDo.getFbaOrderOutputNumber());
//        int count = orderBackService.getBaseMapper().selectCount(orderBackDoLambdaQueryWrapper);
//        if (count > 0) {
//            throw new BizException("该退货单已存在");
//        }
//
//        OrderBackAddReq addReq = new OrderBackAddReq();
//        addReq.setContactName(orderOutputDo.getReceiverName());
//        DicBusinessItemDo businessItemDo = dicBusinessItemDao.selectById(orderOutputDo.getTrackId());
//        if (businessItemDo != null) {
//            addReq.setTrackName(businessItemDo.getDicItemValue());
//        }
//        addReq.setOperateFee(orderOutputDo.getOperateFee());
//        addReq.setOrderOutNumber(orderOutputDo.getFbaOrderOutputNumber());
//        addReq.setShipFee(orderOutputDo.getShipFee());
//        addReq.setShopId(orderOutputDo.getShopId());
//        addReq.setStorageId(orderOutputDo.getStorageId());
//        addReq.setTaxFee(orderOutputDo.getTaxFee());
//        addReq.setTelPhone(orderOutputDo.getTelPhone());
//        addReq.setTrackNumber(orderOutputDo.getTrackNumber());
//
//        List<OrderBackAddItem> items = new ArrayList<>();
//        req.getItems().forEach(orderOutputSalesReturnItem -> {
//            OrderBackAddItem orderBackAddItem = new OrderBackAddItem();
//            orderBackAddItem.setProductId(orderOutputSalesReturnItem.getProductId());
//            orderBackAddItem.setCount(orderOutputSalesReturnItem.getCount());
//            items.add(orderBackAddItem);
//        });
//
//        addReq.setItems(items);
//        orderBackService.add(addReq, userId, companyId);
//    }


    private void handlerOrderBack(FbaOrderOutputDo entityDo, Long userId, Long companyId) {
        OrderBackAddReq req = new OrderBackAddReq();
        req.setContactName(entityDo.getReceiverName());
        DicBusinessItemDo businessItemDo = dicBusinessItemDao.selectById(entityDo.getTrackId());
        if (businessItemDo != null) {
            req.setTrackName(businessItemDo.getDicItemValue());
        }
        req.setOperateFee(entityDo.getOperateFee());
        req.setOrderOutNumber(entityDo.getFbaOrderOutputNumber());
        req.setShipFee(entityDo.getShipFee());
        req.setShopId(entityDo.getShopId());
        req.setStorageId(entityDo.getStorageId());
        req.setTaxFee(entityDo.getTaxFee());
        req.setTelPhone(entityDo.getTelPhone());
        req.setTrackNumber(entityDo.getTrackNumber());

        List<OrderBackAddItem> items = new ArrayList<>();
        LambdaQueryWrapper<FbaOrderOutputProductDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputProductDo::getOrderId, entityDo.getId());
        List<FbaOrderOutputProductDo> orderOutputProductDoList = productDao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(orderOutputProductDoList)) {
            for (FbaOrderOutputProductDo orderOutputProductDo : orderOutputProductDoList) {
                OrderBackAddItem item = new OrderBackAddItem();
                item.setCount(orderOutputProductDo.getCount());
                item.setProductId(orderOutputProductDo.getProductId());
                items.add(item);
            }
        }
        req.setItems(items);

        orderBackService.add(req, userId, companyId);
    }

    //编辑校验
    private void updateCheck(FbaOrderOutputUpdateReq req) {
//        if (!StringUtils.isNotBlank(req.getPostCode()))
//            throw new BizException("缺少邮编");
//        if (!StringUtils.isNotBlank(req.getAddress()))
//            throw new BizException("缺少收货地址");
//        if (!StringUtils.isNotBlank(req.getOrderNo()))
//            throw new BizException("缺少顾客订单号");
        if (req.getShopId() == null) {
            throw new BizExceptionI18("order.no.shop");
        }
        if (req.getStorageId() == null) {
            throw new BizExceptionI18("order.no.storage");
        }
        if (req.getFbaStorageId() == null && req.getStorageType() != null && "fba".equals(req.getStorageType())) {
            throw new BizExceptionI18("pls.choose.fba.storage");
        }
        if (req.getTrackId() == null) {
            throw new BizExceptionI18("pls.choose.track");
        }
        if (req.getPackageList() == null ||
                req.getPackageList().size() < 1) {
            throw new BizExceptionI18("order.no.product");
        }
    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(FbaOrderOutputDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }

    //做修改之后要执行的业务定制处理
    private FbaOrderOutputUpdateReq handlerUpdateAfter(FbaOrderOutputUpdateReq updateReq, FbaOrderOutputDo entityDo) {
        LambdaQueryWrapper<FbaOrderOutputPackageDo> packageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        packageDoLambdaQueryWrapper.eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, updateReq.getId());
        packageDao.delete(packageDoLambdaQueryWrapper);

        LambdaQueryWrapper<FbaOrderOutputProductDo> productDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        productDoLambdaQueryWrapper.eq(FbaOrderOutputProductDo::getOrderId, updateReq.getId());
        productDao.delete(productDoLambdaQueryWrapper);
        StringBuilder sb = new StringBuilder();
        StringBuilder storageSku = new StringBuilder();
        List<FbaOrderOutputPackageUpdateReq> packageUpdateReqs = updateReq.getPackageList();
        for (FbaOrderOutputPackageUpdateReq req : packageUpdateReqs) {
            FbaOrderOutputPackageDo packageDo = new FbaOrderOutputPackageDo();
            BeanUtils.copyProperties(req, packageDo);
            packageDo.setFbaOrderOutputId(updateReq.getId());
            packageDo.setCount(req.getPackageCount());
            packageDao.insert(packageDo);
            if (!sb.toString().contains(packageDo.getPoNumber())) {
                if (sb.length() > 0) {
                    sb.append(",");
                }
                sb.append(packageDo.getPoNumber());
            }
            if (!CollectionUtils.isEmpty(req.getProductList())) {
                for (FbaOrderOutputProductDetail product : req.getProductList()) {
                    ProductInfoDo productInfoDo = productInfoDao.selectById(product.getProductId());
                    if (productInfoDo == null) {
                        throw new BizException(SysConstant.Product_NotExist);
                    }
                    if (storageSku.length() > 0) {
                        storageSku.append(",");
                    }
                    storageSku.append(productInfoDo.getStorageSku());
                    FbaOrderOutputProductDo productDo = new FbaOrderOutputProductDo();
                    if (product.getCount() == null) {
                        product.setCount(0);
                    }
                    BeanUtils.copyProperties(product, productDo);
                    verifyStock(updateReq.getShopId(), updateReq.getStorageId(), product.getProductId(),
                            product.getCount() * req.getPackageCount(), productInfoDo.getCommoditySku());
                    productDo.setOrderId(updateReq.getId());
                    productDo.setPackageId(packageDo.getId());
                    productDao.insert(productDo);
                }
            }

        }
        entityDo.setPoNumber(sb.toString());
        entityDo.setStorageSku(storageSku.toString());
        updateById(entityDo);
//        updateTrackId(entityDo);
        return updateReq;
    }

    @Override
    public int delete(Long id, Long userId) {
        FbaOrderOutputDo entityDo = dao.selectById(id);
        if (entityDo.getStatus() >= DicBusinessItemConstant.fbaOrderBackCheckStatus) {
            throw new BizExceptionI18("order.delete.fair");
        }
        handlerDeleteBefore(entityDo, userId);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(FbaOrderOutputDo entityDo, Long userId) {
        entityDo.setDeleteBy(userId);
        entityDo.setDeleteTime(new Date());
        updateById(entityDo);
    }

    @Override
    public FbaOrderOutputDetailRes detail(Long id, boolean needCanSell) {
        FbaOrderOutputDo entityDo = dao.selectById(id);
        FbaOrderOutputDetailRes res = new FbaOrderOutputDetailRes();
        if (entityDo == null) {
            throw new BizExceptionI18("order.detail.notfound");
        }
        BeanUtils.copyProperties(entityDo, res);
        DicBusinessItemDo itemDo = dicBusinessItemDao.selectById(entityDo.getStatus());
        if (itemDo != null) {
            res.setStatus(itemDo.getDicItemValue());
        }
        res.setStatusId(itemDo.getId().intValue());
        res.setFileUrl(fileService.getFilePath(entityDo.getFileId()));
        res.setProductFileUrl(fileService.getFilePath(entityDo.getProductFileId()));
        res.setOtherFileUrl(fileService.getFilePath(entityDo.getOtherFileId()));
        res.setSignatureFileUrl(fileService.getFilePath(entityDo.getSignatureFileId()));
        return handlerDetailAfter(entityDo, res, needCanSell);
    }

    public FbaOrderOutputDetailRes detail(String orderNumber) {
        LambdaQueryWrapper<FbaOrderOutputDo> wrapper = new LambdaQueryWrapper();
        wrapper.eq(FbaOrderOutputDo::getFbaOrderOutputNumber, orderNumber);
        FbaOrderOutputDo entityDo = dao.selectOne(wrapper);
        FbaOrderOutputDetailRes res = new FbaOrderOutputDetailRes();
        if (entityDo == null) {
            throw new BizExceptionI18("order.detail.notfound.or.delete");
        }
        BeanUtils.copyProperties(entityDo, res);
        DicBusinessItemDo itemDo = dicBusinessItemDao.selectById(entityDo.getStatus());
        if (itemDo != null) {
            res.setStatus(itemDo.getDicItemValue());
        }
        res.setStatusId(itemDo.getId().intValue());
        res.setFileUrl(fileService.getFilePath(entityDo.getFileId()));
        res.setProductFileUrl(fileService.getFilePath(entityDo.getProductFileId()));
        res.setOtherFileUrl(fileService.getFilePath(entityDo.getOtherFileId()));
        res.setSignatureFileUrl(fileService.getFilePath(entityDo.getSignatureFileId()));
        return handlerDetailAfter(entityDo, res, false);
    }

    //查询明细之后要执行的业务定制处理
    private FbaOrderOutputDetailRes handlerDetailAfter(FbaOrderOutputDo entityDo, FbaOrderOutputDetailRes res, boolean needCanSell) {
        res.setShopId(entityDo.getShopId());
        if (shopDao.selectById(entityDo.getShopId()) != null) {
            res.setShop(shopDao.selectById(entityDo.getShopId()).getShopName());
        }
        res.setStorageId(entityDo.getStorageId());
        if (storageDao.selectById(entityDo.getStorageId()) != null) {
            res.setStorage(storageDao.selectById(entityDo.getStorageId()).getStorageName());
        }
        if (dicBusinessItemDao.selectById(entityDo.getTrackId()) != null) {
            res.setTrackName(dicBusinessItemDao.selectById(entityDo.getTrackId()).getDicItemValue());
        }
        res.setPoNumber(entityDo.getPoNumber());
        res.setOrderNo(entityDo.getOrderNo());
        FbaStorageDo fbaStorageDo = fbaStorageDao.selectById(entityDo.getFbaStorageId());
        if (fbaStorageDo != null && entityDo.getReceiverName() == null) {
            res.setReceiverName(fbaStorageDo.getFbaCode() + " " + fbaStorageDo.getFbaName());
        }
        if (entityDo.getDeliveryDate() != null) {
            res.setDeliveryDate(TimeUtils.formatDate(entityDo.getDeliveryDate()));
        }
        res.setOrderNumber(entityDo.getFbaOrderOutputNumber());
//        res.setShipmentTypeName(entityDo.getShipmentType() != null && entityDo.getShipmentType() == 1 ? SHIPMENT_TYPE_1 : SHIPMENT_TYPE_0);
        //查询对应包裹列表
        //package
        List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(new LambdaQueryWrapper<FbaOrderOutputPackageDo>()
                .eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, res.getId()));
        Set<String> poSet = new HashSet<>();
        List<FbaOrderOutputPackageDetail> packageResList = new ArrayList<>();
        //获取库存
        Map<String, String> param = new HashMap<>();
        param.put("storageId", entityDo.getStorageId() + "");
        param.put("shopId", entityDo.getShopId() + "");
        List<StockRecordPageRes> stockList = stockRecordService.getList(param);
        Map<Long, List<StockRecordPageRes>> stockListMap = stockList.stream().collect(Collectors.groupingBy(StockRecordPageRes::getProductInfoId));

        for (FbaOrderOutputPackageDo packageDo : packageDoList) {
            poSet.add(packageDo.getPoNumber());
            FbaOrderOutputPackageDetail packageDetailRes = new FbaOrderOutputPackageDetail();
            BeanUtils.copyProperties(packageDo, packageDetailRes);
            packageDetailRes.setCount(packageDo.getCount());
            packageDetailRes.setSize(packageDo.getLength() + "+" + packageDo.getWidth() + "+" + packageDo.getHeight());
            //product
            List<FbaOrderOutputProductDetail> productResList = new ArrayList<>();
            List<FbaOrderOutputProductDo> productDoList = productDao.selectList(new LambdaQueryWrapper<FbaOrderOutputProductDo>()
                    .eq(FbaOrderOutputProductDo::getPackageId, packageDo.getId()));

            for (FbaOrderOutputProductDo productDetail : productDoList) {
                FbaOrderOutputProductDetail productDetailRes = new FbaOrderOutputProductDetail();

                BeanUtils.copyProperties(productDetail, productDetailRes);
                ProductInfoDo productInfoDo = productInfoDao.selectById(productDetail.getProductId());
                if (productInfoDo != null) {
                    productDetailRes.setCommoditySku(productInfoDo.getCommoditySku());
                    productDetailRes.setStorageSku(productInfoDo.getStorageSku());
                    productDetailRes.setCommodityName(productInfoDo.getCommodityName());
                    if (stockListMap.get(productInfoDo.getId()) != null) {
                        productDetailRes.setCanSellCount(stockListMap.get(productInfoDo.getId()).get(0).getCanSellCount() -
                                stockListMap.get(productInfoDo.getId()).get(0).getNoDelivered() + packageDo.getCount() * productDetail.getCount());
                    } else {
                        productDetailRes.setCanSellCount(0);
                    }
                }
                productResList.add(productDetailRes);
            }

            if (!CollectionUtils.isEmpty(poSet)) {
                List<String> poList = new ArrayList<>(poSet);
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < poList.size(); i++) {
                    if (i >= poList.size() - 1) {
                        stringBuilder.append(poList.get(i));
                    } else {
                        stringBuilder.append(poList.get(i) + ",");
                    }
                }
                res.setPoNumber(stringBuilder.toString());
            }
            packageDetailRes.setProductList(productResList);
            packageResList.add(packageDetailRes);
        }
        res.setPackageList(packageResList);
        //查询日志
        List<OperateRes> operateResList = operateRecordService.getOperateList(entityDo.getId(), 6);
        res.setOperateResList(operateResList);
        return res;
    }

    @Override
    public SingleResult pageInit(Long companyId, Long userId) {
        Map map = new HashMap();
        map.put("storageList", storageService.getJpList());
        List<Long> ids = new ArrayList<>();
        LambdaQueryWrapper<DicBusinessItemDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.fbaOrderOutPutTruck);
        List<DicBusinessItemDo> trackCompanyList = dicBusinessItemDao.selectList(wrapper);
        List<IdAndNameEntity> trackList = new ArrayList<>();
        trackList.add(new IdAndNameEntity(StaticDict.Track_Type.SagawaExpress.getValue().intValue(),
                StaticDict.Track_Type.SagawaExpress.getText()));
        trackList.add(new IdAndNameEntity(StaticDict.Track_Type.YamatoExpress.getValue().intValue(),
                StaticDict.Track_Type.YamatoExpress.getText()));
        for (DicBusinessItemDo itemDo :
                trackCompanyList) {
            trackList.add(new IdAndNameEntity(itemDo.getId().intValue(), itemDo.getDicItemValue()));
        }
        map.put("trackList", trackList);

        List<Map> shopList = shopService.selectShopListInit(userId, companyId);
        LambdaQueryWrapper<DicBusinessItemDo> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.fbaOrderOutputStatus);
        List<DicBusinessItemDo> dicBusinessItemDos = dicBusinessItemDao.selectList(wrapper1);
        map.put("shopList", shopList);
        map.put("status", dicBusinessItemDos);
        return SingleResult.success(map);
    }

    @Override
    public List<FbaOrderOutputListRes> getList(Map<String, String> map) {
        QueryWrapper<FbaOrderOutputDo> wrapper = queryBuild(map);
        List<FbaOrderOutputDo> list = this.list(wrapper);
        List<FbaOrderOutputListRes> result = handlerListAfter(list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        QueryWrapper<FbaOrderOutputDo> wrapper = queryBuild(map);
        IPage<FbaOrderOutputDo> page = pageInit(map);
        page = this.page(page, wrapper);
        List<FbaOrderOutputListRes> resList = handlerListAfter(page.getRecords());
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        result.setMapInfo(countStatus(map));
        return result;
    }

    private Map countStatus(Map<String, String> map) {
        List<Map> result = new ArrayList<>();
        map.put("status", "");

        Map mapTotal = new HashMap();
        List<FbaOrderOutputDo> list = dao.selectList(queryBuild(map));
        mapTotal.put("count", list.size());
        mapTotal.put("name", StringsUtil.createI18Message("全部"));
        result.add(mapTotal);

        Map<Long, List<FbaOrderOutputDo>> listMap = list.stream().collect(Collectors.groupingBy(FbaOrderOutputDo::getStatus));
        LambdaQueryWrapper<DicBusinessItemDo> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.fbaOrderOutputStatus);
        wrapper1.orderByAsc(DicBusinessItemDo::getSort);
        for (DicBusinessItemDo itemDo : dicBusinessItemDao.selectList(wrapper1)) {
            Map map1 = new HashMap();
            map1.put("id", itemDo.getId());
            if (listMap.get(itemDo.getId()) != null) {
                map1.put("count", listMap.get(itemDo.getId()).size());
            } else {
                map1.put("count", 0);
            }
            map1.put("name", StringsUtil.createI18Message(itemDo.getDicItemValue()));
            result.add(map1);
        }


        Map map2 = new HashMap();
        map2.put("census", result);
        return map2;
    }

    //查询分页列表之后对列表数据的处理
    private List<FbaOrderOutputListRes> handlerListAfter(List<FbaOrderOutputDo> list) {
        List<FbaOrderOutputListRes> result = new ArrayList<>();
        for (FbaOrderOutputDo orderOutputDo :
                list) {
            FbaOrderOutputListRes listRes = new FbaOrderOutputListRes();
            BeanUtils.copyProperties(orderOutputDo, listRes);
            StorageDo storageDo = storageDao.selectById(orderOutputDo.getStorageId());
            if (storageDo != null) {
                listRes.setStorageName(storageDo.getStorageName());
            }
            FbaStorageDo fbaStorageDo = fbaStorageDao.selectById(orderOutputDo.getFbaStorageId());
            if (orderOutputDo.getStorageType().equals(SysConstant.FBA_ADDRESS) && fbaStorageDo != null) {
                listRes.setFbaStorageName(fbaStorageDo.getFbaCode());
            } else {
                listRes.setFbaStorageName(orderOutputDo.getReceiverName());
            }
            DicBusinessItemDo dic = dicBusinessItemDao.selectById(orderOutputDo.getTrackId());
            if (dic != null) {
                DicBusinessItemDo dicBusinessItemDo = dicBusinessItemDao.selectById(dic.getParentId());
                if (dicBusinessItemDo != null)
                    listRes.setTrackName(dicBusinessItemDo.getDicItemValue());
                else
                    listRes.setTrackName(dic.getDicItemValue());
            }
            DicBusinessItemDo dicBusinessItemDo = dicBusinessItemDao.selectById(orderOutputDo.getStatus());
            if (dicBusinessItemDo != null) {
                listRes.setStatus(dicBusinessItemDo.getDicItemValue());
                listRes.setStatusNumber(orderOutputDo.getStatus());
            }
//            if (1 == orderOutputDo.getShipmentType()) {
//                listRes.setShipmentTypeName(SHIPMENT_TYPE_1);
//            } else {
//                listRes.setShipmentTypeName(SHIPMENT_TYPE_0);
//            }
            listRes.setNumber(orderOutputDo.getFbaOrderOutputNumber());
            listRes.setSendDate(TimeUtils.formatDate(orderOutputDo.getSendDate()));

            if (StringUtils.isBlank(orderOutputDo.getPoNumber())) {
                LambdaQueryWrapper<FbaOrderOutputPackageDo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, orderOutputDo.getId());
                List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(wrapper);
                StringBuilder sb = new StringBuilder();
                for (FbaOrderOutputPackageDo packageDo : packageDoList) {
                    if (StringUtils.isBlank(packageDo.getPoNumber())) {
                        continue;
                    }
                    if (!sb.toString().contains(packageDo.getPoNumber())) {
                        if (sb.length() > 0) {
                            sb.append(",");
                        }
                        sb.append(packageDo.getPoNumber());
                    }
                }
                listRes.setPoNumber(sb.toString());
            } else {
                listRes.setPoNumber(orderOutputDo.getPoNumber());
            }

            double volume = 0;
            double weight = 0;
            int packageCount = 0;
            LambdaQueryWrapper<FbaOrderOutputPackageDo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, orderOutputDo.getId());
            List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(wrapper);
            if (!CollectionUtils.isEmpty(packageDoList)) {
                packageCount = packageDoList.stream().mapToInt(FbaOrderOutputPackageDo::getCount).sum();
                for (FbaOrderOutputPackageDo packageDo : packageDoList) {
                    volume += packageDo.getHeight() * packageDo.getWidth() * packageDo.getLength() * packageDo.getCount() / 1000000;
                    weight += packageDo.getWeight() * packageDo.getCount();
                }
            }
            listRes.setVolume(String.valueOf(numberfromat(volume)));
            listRes.setWeight(numberfromat(weight));
            listRes.setPackageCount(packageCount);
            listRes.setReceiverName(orderOutputDo.getReceiverName());
            listRes.setShipPrice(orderOutputDo.getShipFee());
            result.add(listRes);
        }
        return result;
    }


    private double getProductVolumeAndWeight(FbaOrderOutputDo orderOutputDo, int index) {
        double volume = 0;
        double weight = 0;
        LambdaQueryWrapper<FbaOrderOutputPackageDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, orderOutputDo.getId());
        List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(packageDoList)) {
            for (FbaOrderOutputPackageDo packageDo : packageDoList) {
                volume += packageDo.getHeight() * packageDo.getWidth() * packageDo.getLength() * packageDo.getCount();
                weight += packageDo.getWeight() * packageDo.getCount();
            }
        }

        BigDecimal b = new BigDecimal(index == 0 ? volume / 1000000 : weight);
        double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

        return f1;
    }

    private IPage<FbaOrderOutputDo> pageInit(Map<String, String> map) {
        IPage<FbaOrderOutputDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<FbaOrderOutputDo> queryBuild(Map<String, String> map) {
        QueryWrapper<FbaOrderOutputDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("keyword"))) {
            wrapper.or(orderOutputDoQueryWrapper -> orderOutputDoQueryWrapper.like("order_no", map.get("keyword").trim()).or(true)
                    .like("fba_order_output_number", map.get("keyword").trim()).or(true)
                    .like("tips", map.get("keyword").trim()).or(true)
                    .like("po_number", map.get("keyword").trim()).or(true)
                    .like("track_number", map.get("keyword").trim()).or(true).like("storage_sku", map.get("keyword")));
        }
        if (StringUtils.isNotBlank(map.get("status"))) {
            wrapper.eq("status", map.get("status"));
        }
        if (StringUtils.isNotBlank(map.get("startDate"))) {
            wrapper.ge("send_date", map.get("startDate"));
        }
        if (StringUtils.isNotBlank(map.get("endDate"))) {
            wrapper.le("send_date", map.get("endDate"));
        }
        if (StringUtils.isNotBlank(map.get("storageId"))) {
            wrapper.eq("storage_id", map.get("storageId"));
        }

        if (StringUtils.isNotBlank(map.get("shopId"))) {
            wrapper.eq("shop_id", map.get("shopId"));
        }
//        if (StringUtils.isNotBlank(map.get("orderType"))) {
//            wrapper.eq("order_type", map.get("orderType"));
//        }
        if (StringUtils.isNotBlank(map.get("storageType"))) {
            wrapper.eq("storage_type", map.get("storageType"));
        }
        wrapper.eq("company_id", map.get("companyId"));

        if (StringUtils.isNotBlank(map.get("trackId"))) {
            List<DicBusinessItemDo> itemDoList = dicBusinessItemDao.selectList(new LambdaQueryWrapper<DicBusinessItemDo>()
                    .eq(DicBusinessItemDo::getParentId, map.get("trackId")));
            StringBuilder last = new StringBuilder(" and (");
            for (int i = 0; i < itemDoList.size(); i++) {
                if (i != 0) {
                    last.append(" or ");
                }
                last.append(" track_id = ").append(itemDoList.get(i).getId());
            }
            last.append(") order by id desc");
            wrapper.last(last.toString());
//            wrapper.eq("track_id", map.get("trackId"));
        } else {
            wrapper.orderByDesc("id");
        }
        return wrapper;
    }

    @Override
    public void appointmentStorageTime(FbaOrderOutputUpdateTimeReq req) {
        FbaOrderOutputDo orderOutputDo = dao.selectById(req.getId());
        orderOutputDo.setAppointmentStorageTime(req.getDate());
        dao.updateById(orderOutputDo);
    }

    @Override
    public void appointmentCarTime(FbaOrderOutputUpdateTimeReq req) {
        FbaOrderOutputDo orderOutputDo = dao.selectById(req.getId());
        orderOutputDo.setAppointmentCarTime(req.getDate());
        dao.updateById(orderOutputDo);
    }

    @Override
    public SingleResult dealwithExcel(MultipartFile file, int shopId, int storageId, Long userid, Long companyId) {
        sufficientFundsCheck(companyId);
        List<String> tips = new ArrayList<>();
        List<FbaOrderOutputExcelImport> excelImportList = new ArrayList<>();
        if (StringUtils.isEmpty(file.getName())) {
            throw new BizExceptionI18("file.name.null");
        }
        if (shopId == 0) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_SHOP);
        }
        if (storageId == 0) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_STORAGE);
        }
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        if (!GlobalConstants.IMG_TYPE_XLS.equals(suffix.toUpperCase()) &&
                !GlobalConstants.IMG_TYPE_XLSX.equals(suffix.toUpperCase())) {
            throw new BizExceptionI18("file.form.incorrect");
        }
        try {
            excelImportList = ExcelUtils.importExcel(file, 0, 1, FbaOrderOutputExcelImport.class);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BizException(e.getMessage());
        }
        if (excelImportList == null) {
            throw new BizExceptionI18("file.formWork.incorrect");
        }
        for (int i = 0; i < excelImportList.size(); i++) {
            FbaOrderOutputExcelImport excelData = excelImportList.get(i);
            if (StringUtils.isBlank(excelData.getPostCode())) {
                continue;
            }
            try {
                dealwithExcelData(excelData, shopId, storageId, userid);
            } catch (BizException e) {
                e.printStackTrace();
//                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                tips.add(e.getMessage());
            }
        }
        if (tips.size() > 0) {
            return SingleResult.failure("300", SysConstant.EXPORT_OUT_ORDER_SUCCESS_ID, tips, excelImportList.size() - tips.size());
        } else {
            return SingleResult.success(SysConstant.IMPORT_OUT_ORDER_SUCCESS_ID, null, excelImportList.size());
        }

    }

    /**
     * @param map
     * @param req
     * @param response
     * @throws IOException
     */
    @Override
    public void exportExcel(Map<String, String> map, OrderOutputExcelReq req, HttpServletResponse response) throws IOException {
        List<FbaOrderOutputDo> orderOutputDoList = null;
        if (CollectionUtils.isEmpty(req.getIds())) {
            QueryWrapper<FbaOrderOutputDo> wrapper = queryBuild(map);
            orderOutputDoList = this.baseMapper.selectList(wrapper);
        } else {
            LambdaQueryWrapper<FbaOrderOutputDo> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(FbaOrderOutputDo::getId, req.getIds()).eq(FbaOrderOutputDo::getCompanyId, map.get("companyId")).orderByDesc(FbaOrderOutputDo::getId);
            orderOutputDoList = this.baseMapper.selectList(wrapper);
        }

        if (orderOutputDoList.size() > 500) {
//            response.sendError(500, "数据超过500条，请分日期导出");
            throw new BizExceptionI18(SysConstant.Order_Count_Oversize);
        }
        List<FbaOrderOutputExcelExportVo> excelExportVoList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(orderOutputDoList)) {
            for (FbaOrderOutputDo orderOutputDo : orderOutputDoList) {
                FbaOrderOutputExcelExportVo excelExportVo = new FbaOrderOutputExcelExportVo();
                BeanUtils.copyProperties(orderOutputDo, excelExportVo);
                excelExportVo.setOrderNumber(orderOutputDo.getFbaOrderOutputNumber());
                if (DicBusinessItemConstant.fbaOrderCancelStatus.equals(orderOutputDo.getStatus())) {
                    excelExportVo.setShipFee(0d);
                    excelExportVo.setOperateFee(0d);
                    excelExportVo.setOutFee(0d);
                } else {
                    excelExportVo.setCancelFee(0d);
                    excelExportVo.setLabelFee(0d);
                    excelExportVo.setLaborFee(0d);
                }
                DicBusinessItemDo businessItemDo = dicBusinessItemDao.selectById(orderOutputDo.getStatus());
                if (businessItemDo != null) {
                    excelExportVo.setStatus(businessItemDo.getDicItemValue());
                }
                ShopDo shopDo = shopDao.selectById(orderOutputDo.getShopId());
                if (shopDo != null) {
                    excelExportVo.setShopName(shopDo.getShopName());
                }
                StorageDo storageDo = storageDao.selectById(orderOutputDo.getStorageId());
                if (storageDo != null) {
                    excelExportVo.setStorageName(storageDo.getStorageName());
                }
                FbaStorageDo fbaStorageDo = fbaStorageDao.selectById(orderOutputDo.getFbaStorageId());
                if (orderOutputDo.getStorageType().equals(SysConstant.FBA_ADDRESS) && fbaStorageDo != null) {
                    excelExportVo.setFbaStorageCode(fbaStorageDo.getFbaCode());
                } else {
                    excelExportVo.setFbaStorageCode(orderOutputDo.getReceiverName());
                }
                DicBusinessItemDo track = dicBusinessItemDao.selectById(orderOutputDo.getTrackId());
                if (track != null) {
                    excelExportVo.setTrackName(track.getDicItemValue());
                }
                excelExportVo.setTrackNumber(orderOutputDo.getTrackNumber());
                int packageCount = packageDao.selectCountByOrderId(orderOutputDo.getId());
                excelExportVo.setVolume(String.valueOf(getProductVolumeAndWeight(orderOutputDo, 0)));
                excelExportVo.setWeight(getProductVolumeAndWeight(orderOutputDo, 1));
                excelExportVo.setPackageCount(packageCount);
                excelExportVo.setSendTime(orderOutputDo.getSendTime());
                excelExportVo.setAppointmentStorageTime(orderOutputDo.getAppointmentStorageTime());


//                //package
                LambdaQueryWrapper<FbaOrderOutputPackageDo> packageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                packageDoLambdaQueryWrapper.eq(FbaOrderOutputPackageDo::getFbaOrderOutputId, orderOutputDo.getId());
                List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(packageDoLambdaQueryWrapper);
                if (!CollectionUtils.isEmpty(packageDoList)) {
                    List<FbaOrderOutputPackageExcelExportVo> packageExcelExportVoList = new ArrayList<>();
                    for (FbaOrderOutputPackageDo packageDo : packageDoList) {
                        FbaOrderOutputPackageExcelExportVo packageExcelExportVo = new FbaOrderOutputPackageExcelExportVo();
                        BeanUtils.copyProperties(packageDo, packageExcelExportVo);
                        LambdaQueryWrapper<FbaOrderOutputProductDo> productDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                        productDoLambdaQueryWrapper.eq(FbaOrderOutputProductDo::getPackageId, packageDo.getId());
                        List<FbaOrderOutputProductDo> productDoList = productDao.selectList(productDoLambdaQueryWrapper);
                        if (!CollectionUtils.isEmpty(productDoList)) {
                            List<FbaOrderOutputProductExcelExportVo> productExcelExportVoList = new ArrayList<>();
                            for (FbaOrderOutputProductDo productDo : productDoList) {
                                FbaOrderOutputProductExcelExportVo productExcelExportVo = new FbaOrderOutputProductExcelExportVo();
                                BeanUtils.copyProperties(productDo, productExcelExportVo);
                                ProductInfoDo productInfoDo = productInfoDao.selectById(productDo.getProductId());
                                if (productInfoDo != null) {
                                    productExcelExportVo.setCommoditySku(productInfoDo.getCommoditySku());
                                    productExcelExportVo.setCommodityName(StringUtils.isNotBlank(productInfoDo.getCommodityName()) ? productInfoDo.getCommodityName() : productInfoDo.getProductName());
                                    productExcelExportVo.setStorageSku(productInfoDo.getStorageSku());
                                }
                                productExcelExportVoList.add(productExcelExportVo);
                            }
                            packageExcelExportVo.setProductExcelExportVoList(productExcelExportVoList);
                        }
                        packageExcelExportVoList.add(packageExcelExportVo);
                    }
                    excelExportVo.setPackageExcelExportVoList(packageExcelExportVoList);
                }
                excelExportVoList.add(excelExportVo);
            }
        }

        ExcelUtils.exportExcel(excelExportVoList, FbaOrderOutputExcelExportVo.class, "FBA出库订单", new ExportParams(), response);
    }


    @Override
    public List<FbaExcelImportPackageRes> importExcel(MultipartFile file, Long storageId, Long shopId, Long companyId) throws IOException {
        if (storageId == null) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_STORAGE);
        }
        if (shopId == null) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_SHOP);
        }
        if (file == null) {
            throw new BizExceptionI18("file.name.null");
        }
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        if (!GlobalConstants.IMG_TYPE_XLS.equals(suffix.toUpperCase()) &&
                !GlobalConstants.IMG_TYPE_XLSX.equals(suffix.toUpperCase())) {
            throw new BizExceptionI18("file.form.incorrect");
        }
        List<FbaExcelImportVo> excelImportVoList = ExcelUtils.importExcel(file, 0, 1, FbaExcelImportVo.class);
        if (excelImportVoList.size() < 1) {
            throw new BizExceptionI18("file.formWork.incorrect");
        }
        List<FbaExcelImportPackageRes> packageList = new ArrayList<>();
        Map<Long, List<FbaExcelImportVo>> map = excelImportVoList.stream()
                .filter(product -> product.getPackageCount() != null && product.getLength() != null && product.getWidth() != null)
                .collect(Collectors.groupingBy(FbaExcelImportVo::getPackageNo));
        if (!CollectionUtils.isEmpty(map)) {
            //获取库存
            Map<String, String> param = new HashMap();
            param.put("storageId", storageId + "");
            param.put("shopId", shopId + "");
            List<StockRecordPageRes> stockList = stockRecordService.getList(param);
            Map<Long, List<StockRecordPageRes>> stockListMap = stockList.stream().collect(Collectors.groupingBy(StockRecordPageRes::getProductInfoId));


            for (Long packageNo : map.keySet()) {
                List<FbaExcelImportVo> excelImportVos = map.get(packageNo);
                if (!CollectionUtils.isEmpty(excelImportVos)) {
                    FbaExcelImportPackageRes packageAdd = new FbaExcelImportPackageRes();
                    packageAdd.setPackageCount(excelImportVos.get(0).getPackageCount());
                    packageAdd.setPackageHeight(excelImportVos.get(0).getHeight().floatValue());
                    packageAdd.setPackageLenght(excelImportVos.get(0).getLength().floatValue());
                    packageAdd.setPackageWidth(excelImportVos.get(0).getWidth().floatValue());
                    packageAdd.setPackageWeight(excelImportVos.get(0).getWeight().floatValue());
                    packageAdd.setPoNumber(excelImportVos.get(0).getPoNumber());
                    packageAdd.setUpcNumber(excelImportVos.get(0).getUpcNumber());
                    packageAdd.setTips(excelImportVos.get(0).getTips());

                    List<JSONObject> productAddList = new ArrayList<>();
                    for (FbaExcelImportVo excelImportVo : excelImportVos) {
                        //商品
                        if (StringUtils.isBlank(excelImportVo.getCommoditySku())) {
                            continue;
                        }
                        JSONObject productAdd = new JSONObject();
                        LambdaQueryWrapper<ProductInfoDo> wrapper = new LambdaQueryWrapper<>();
                        wrapper.or(productWrapper -> {
                            productWrapper.eq(ProductInfoDo::getCommoditySku, excelImportVo.getCommoditySku()).or()
                                    .eq(ProductInfoDo::getStorageSku, excelImportVo.getCommoditySku());
                        });
                        wrapper.eq(ProductInfoDo::getCompanyId, companyId);
                        ProductInfoDo productInfoDo = productInfoDao.selectOne(wrapper);
                        if (productInfoDo != null) {
                            productAdd.put("productId", productInfoDo.getId());
                            productAdd.put("commoditySku", productInfoDo.getCommoditySku());
                            productAdd.put("storageSku", productInfoDo.getStorageSku());
                            productAdd.put("productName", productInfoDo.getCommodityName());
//                            productAdd.put("createTime", productInfoDo.getCreateTime());
                            if (stockListMap.get(productInfoDo.getId()) != null) {
                                productAdd.put("canSellCount", stockListMap.get(productInfoDo.getId()).get(0).getCanSellCount() - stockListMap.get(productInfoDo.getId()).get(0).getNoDelivered());
                                productAdd.put("createTime", stockListMap.get(productInfoDo.getId()).get(0).getUpdateTime());

                            } else {
                                productAdd.put("canSellCount", 0);
                            }
                        } else {
                            productAdd.put("productId", "");
                            productAdd.put("commoditySku", "产品不存在，请检查SKU" + excelImportVo.getCommoditySku());
                            productAdd.put("productName", "");
                            productAdd.put("storageSku", "");
                            productAdd.put("createTime", "");
                            productAdd.put("canSellCount", 0);

                        }
                        productAdd.put("count", excelImportVo.getCount());

                        productAddList.add(productAdd);
                    }

                    packageAdd.setProductDetailList(productAddList);

                    packageList.add(packageAdd);
                }
            }
        }

        return packageList;
    }

    private void dealwithExcelData(FbaOrderOutputExcelImport excelData, int shopId, int storageId, Long userid) {
        String value = checkOrderNo(excelData.getOrderNo());
        if (value != null) {
            throw new BizExceptionI18("order.existed.number_id");
        }
        FbaOrderOutputDo outputDo = new FbaOrderOutputDo();
        outputDo.setSendDate(new Date());
        outputDo.setStatus(DicBusinessItemConstant.fbaInCreateState);
        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_SHOP);
        }
        if (StringUtils.isEmpty(excelData.getCommoditySku1())) {
            throw new BizExceptionI18(SysConstant.SKU_NO_EXISTED, excelData.getOrderNo());
        }
        outputDo.setShopId((long) shopId);
        outputDo.setCompanyId(shopDo.getCompanyId());
        outputDo.setStorageId((long) storageId);
//        outputDo.setOrderType(1);
        outputDo.setOrderNo(excelData.getOrderNo().trim().replaceAll("\\n", ""));
        outputDo.setCreateBy(userid);
        outputDo.setCreateTime(new Date());
        outputDo.setPostCode(excelData.getPostCode().trim().replaceAll("\\n", ""));
        outputDo.setTelPhone(excelData.getTelPhone());
        outputDo.setArea(excelData.getArea());
        outputDo.setAddress(excelData.getAddress());
        outputDo.setReceiverName(excelData.getReceiverName());
        if (StringUtils.isNotBlank(excelData.getDeliveryDate())) {
            outputDo.setDeliveryDate(TimeUtils.parseDate(excelData.getDeliveryDate()));
        }
        outputDo.setDeliveryTime(excelData.getDeliveryTime());
        outputDo.setTips(excelData.getTips());
        outputDo.setCod(excelData.getCod());
//        if (SHIPMENT_TYPE_1.equals(excelData.getShipmentType())) {
//            outputDo.setShipmentType(1);
//        } else {
//            outputDo.setShipmentType(0);
//        }
//        outputDo.setTrackId(8l);
        save(outputDo);
        operateRecordService.operateAddRecord(SysConstant.OPERATE_CREATE_FBA, outputDo.getId(), userid, 6);
        try {
            dealwithExcelProduct(outputDo, excelData, shopDo.getCompanyId());
        } catch (BizException e) {
            e.printStackTrace();
            dao.deleteById(outputDo.getId());
            throw new BizException(e.getMessage());
        }
    }

    private String checkOrderNo(String orderNo) {
        LambdaQueryWrapper<FbaOrderOutputDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputDo::getOrderNo, orderNo);
        List<FbaOrderOutputDo> list = baseMapper.selectList(wrapper);
        if (list == null || list.size() < 1) {
            return null;
        } else {
            return orderNo + "订单已存在";
        }
    }

    private String checkOrderNo(String orderNo, List<OrderOutputProductAddReq> productList) {
        LambdaQueryWrapper<FbaOrderOutputDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputDo::getOrderNo, orderNo);
        List<FbaOrderOutputDo> list = baseMapper.selectList(wrapper);
        if (list == null || list.size() < 1) {
            return null;
        } else {
            for (FbaOrderOutputDo orderOutputDo :
                    list) {
                for (OrderOutputProductAddReq productAdd :
                        productList) {
                    LambdaQueryWrapper<FbaOrderOutputProductDo> productWrapper = new LambdaQueryWrapper<>();
                    productWrapper.eq(FbaOrderOutputProductDo::getProductId, productAdd.getProductId());
                    productWrapper.eq(FbaOrderOutputProductDo::getOrderId, orderOutputDo.getId());
                    List<FbaOrderOutputProductDo> productDoList = productDao.selectList(productWrapper);
                    if (productDoList != null && productDoList.size() > 0) {
                        return String.format("%s(%s)已存在", orderNo, productInfoDao.selectById(productAdd.getProductId()).getCommoditySku());
                    }
                }
            }
            return null;
        }
    }

    private void dealwithExcelProduct(FbaOrderOutputDo outputDo, FbaOrderOutputExcelImport excelData, Long
            companyId) {
        FbaOrderOutputPackageDo packageDo = new FbaOrderOutputPackageDo();
        packageDo.setFbaOrderOutputId(outputDo.getId());
        packageDo.setCreateBy(outputDo.getCreateBy());
        packageDo.setCreateTime(new Date());
        packageDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
        packageDao.insert(packageDo);
        //todo 产品数量过多时需要人工审核，状态改为-1
        if (StringUtils.isNotBlank(excelData.getCommoditySku1())) {
            ProductInfoDo productInfoDo1 = productInfoDao.selectById(getProductId(excelData.getCommoditySku1(), companyId));
            if (productInfoDo1 == null) {
                throw new BizExceptionI18("no.product.info_id", excelData.getCommoditySku1());
            }
            FbaOrderOutputProductDo outputProductDo1 = new FbaOrderOutputProductDo();
            outputProductDo1.setProductId(productInfoDo1.getId());
            outputProductDo1.setCount(excelData.getCount1());
//        outputProductDo1.setCommoditySku(productInfoDo.getCommoditySku());
            outputProductDo1.setOrderId(outputDo.getId());
            outputProductDo1.setPackageId(packageDo.getId());
            outputProductDo1.setCreateBy(outputDo.getCreateBy());
            outputProductDo1.setCreateTime(new Date());
            outputProductDo1.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);

            String productSku = "";
            ProductInfoDo productInfoDo = productInfoDao.selectById(outputProductDo1.getProductId());
            if (productInfoDo != null) {
                productSku = productInfoDo.getCommoditySku();
            }
            verifyStock(outputDo.getShopId(), outputDo.getStorageId(), outputProductDo1.getProductId(), outputProductDo1.getCount(),
                    productSku);
            productDao.insert(outputProductDo1);
        } else {
            throw new BizExceptionI18("no.product.info_id", excelData.getCommoditySku1());
        }
        //产品2
        if (StringUtils.isNotBlank(excelData.getCommoditySku2())) {
            ProductInfoDo productInfoDo2 = productInfoDao.selectById(getProductId(excelData.getCommoditySku2(), companyId));
            if (productInfoDo2 == null) {
                throw new BizExceptionI18("no.product.info_id", excelData.getCommoditySku2());
            }
            FbaOrderOutputProductDo outputProductDo2 = new FbaOrderOutputProductDo();
            outputProductDo2.setProductId(productInfoDo2.getId());
            outputProductDo2.setCount(excelData.getCount2());
//        outputProductDo2.setCommoditySku(productInfoDo.getCommoditySku());
            outputProductDo2.setOrderId(outputDo.getId());
            outputProductDo2.setPackageId(packageDo.getId());
            outputProductDo2.setCreateBy(outputDo.getCreateBy());
            outputProductDo2.setCreateTime(new Date());
            outputProductDo2.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
            String productSku = "";
            ProductInfoDo productInfoDo = productInfoDao.selectById(outputProductDo2.getProductId());
            if (productInfoDo != null) {
                productSku = productInfoDo.getCommoditySku();
            }
            verifyStock(outputDo.getShopId(), outputDo.getStorageId(), outputProductDo2.getProductId(), outputProductDo2.getCount(),
                    productSku);
            productDao.insert(outputProductDo2);
        }
        //产品3
        if (StringUtils.isNotBlank(excelData.getCommoditySku3())) {
            ProductInfoDo productInfoDo3 = productInfoDao.selectById(getProductId(excelData.getCommoditySku3(), companyId));
            if (productInfoDo3 == null) {
                throw new BizExceptionI18("no.product.info_id", excelData.getCommoditySku3());
            }
            FbaOrderOutputProductDo outputProductDo3 = new FbaOrderOutputProductDo();
            outputProductDo3.setProductId(productInfoDo3.getId());
            outputProductDo3.setCount(excelData.getCount3());
//        outputProductDo3.setCommoditySku(productInfoDo.getCommoditySku());
            outputProductDo3.setOrderId(outputDo.getId());
            outputProductDo3.setPackageId(packageDo.getId());
            outputProductDo3.setCreateBy(outputDo.getCreateBy());
            outputProductDo3.setCreateTime(new Date());
            outputProductDo3.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
            String productSku = "";
            ProductInfoDo productInfoDo = productInfoDao.selectById(outputProductDo3.getProductId());
            if (productInfoDo != null) {
                productSku = productInfoDo.getCommoditySku();
            }
            verifyStock(outputDo.getShopId(), outputDo.getStorageId(), outputProductDo3.getProductId(), outputProductDo3.getCount(),
                    productSku);
            productDao.insert(outputProductDo3);
        }
        //产品4
        if (StringUtils.isNotBlank(excelData.getCommoditySku4())) {
            ProductInfoDo productInfoDo4 = productInfoDao.selectById(getProductId(excelData.getCommoditySku4(), companyId));
            if (productInfoDo4 == null) {
                throw new BizExceptionI18("no.product.info_id", excelData.getCommoditySku4());
            }
            FbaOrderOutputProductDo outputProductDo4 = new FbaOrderOutputProductDo();
            outputProductDo4.setProductId(productInfoDo4.getId());
            outputProductDo4.setCount(excelData.getCount4());
//        outputProductDo4.setCommoditySku(productInfoDo.getCommoditySku());
            outputProductDo4.setOrderId(outputDo.getId());
            outputProductDo4.setPackageId(packageDo.getId());
            outputProductDo4.setCreateBy(outputDo.getCreateBy());
            outputProductDo4.setCreateTime(new Date());
            outputProductDo4.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
            productDao.insert(outputProductDo4);
        }
        outputDo.setFbaOrderOutputNumber(OrderCodeUtil.getOrderOutNumber(outputDo.getId()));
        updateTrackId(outputDo);
    }

    private String updateTrackId(FbaOrderOutputDo outputDo) {
        List<OrderOutputPackageDo> packageDoListCount = new ArrayList<>();
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("order_id", outputDo.getId());
        List<OrderOutputProductDo> productDoList = productDao.selectList(wrapper);
        if (productDoList == null) {
            return "未找到产品信息";
        }
        double[] size = mShipPriceService.getMulitSkuSize(productDoList);
        StorageDo storageDo = storageDao.selectById(outputDo.getStorageId());
        List<ShipPriceDo> shipPrices = new ArrayList<>();
        CompanyDo companyDo = mCompanyDao.selectById(outputDo.getCompanyId());
        if (size[1] > 3 && size[2] > 3 && size[0] + size[1] + size[2] <= 55 && (outputDo.getCod() == null || outputDo.getCod() < 1)) {
//            shipPrices = mShipPriceService.queryByRegionAndSize(outputDo.getPostCode(), size[3], 59, size[0], size[1], size[2], outputDo.getStorageId(), 1);
        } else if (size[0] + size[1] + size[2] <= SysConstant.OUT_MAX_MUTIL_PACKAGE_SIZE || size[3] <= SysConstant.OUT_MAX_MUTIL_PACKAGE_WEIGHT) {
            shipPrices = mShipPriceService.queryByRegionAndSize(outputDo.getPostCode(),
                    size, 0, 0, outputDo.getStorageId(), 1, outputDo.getCompanyId());
        } else {//捆包尺寸超大
            packageDoListCount = getPackageSizeInfoCount(productDoList, size);
        }
        if (shipPrices == null || shipPrices.size() < 1) {
            //未找到费用信息，请人工处理
            outputDo.setStatus(DicBusinessItemConstant.fbaInCreateState);
            outputDo.setTrackId(DicBusinessItemConstant.sagawaExpress);
        } else {
            if (outputDo.getTrackId() == null || outputDo.getTrackId() == 0) {
                outputDo.setTrackId(mDiminDao.selectById(shipPrices.get(0).getDimensId()).getTrackId());
            }
            outputDo.setStatus(DicBusinessItemConstant.fbaOrderBackCheckStatus);
        }
        if (!"1".equals(storageDo.getSupportShip())) {
            outputDo.setTrackId(DicBusinessItemConstant.sagawaExpress);
        }
        wrapper = new QueryWrapper();

        wrapper.eq("order_output_id", outputDo.getId());
        List<FbaOrderOutputPackageDo> packageDoList = packageDao.selectList(wrapper);
        if (packageDoList == null) {
            return "未找到产品信息";
        }
        if (packageDoList.size() > 1) {

        } else if (packageDoList.size() == 1) {
            FbaOrderOutputPackageDo packageDo = packageDoList.get(0);
            packageDo.setLength(size[0]);
            packageDo.setWidth(size[1]);
            packageDo.setHeight(size[2]);
            packageDo.setWeight(size[3]);
            packageDo.setCount(packageDoListCount.size());
            packageDao.updateById(packageDo);
        }
//        Object res = new Object();
//        BeanUtils.copyProperties(entityDo, res);
//        return res;
        updateById(outputDo);
        return null;
    }

    /**
     * 获取包裹捆包信息
     *
     * @param productDoList
     * @param size
     * @return
     */
    private List<OrderOutputPackageDo> getPackageSizeInfoCount(List<OrderOutputProductDo> productDoList,
                                                               double[] size) {
        size = new double[4];
        List<OrderOutputPackageDo> packageDoList = new ArrayList<>();
        for (OrderOutputProductDo productDo :
                productDoList) {
            for (int i = 0; i < productDo.getCount(); i++) {
                size = mShipPriceService.countSameSkuSize(size, productDo.getProductId(), 1);
                if (size[0] + size[1] + size[2] > SysConstant.OUT_MAX_MUTIL_PACKAGE_SIZE || size[3] > SysConstant.OUT_MAX_MUTIL_PACKAGE_WEIGHT) {
                    OrderOutputPackageDo packageDo = new OrderOutputPackageDo();
                    packageDo.setLength(size[0]);
                    packageDo.setWidth(size[1]);
                    packageDo.setHeight(size[2]);
                    packageDo.setWeight(size[3]);
                    packageDoList.add(packageDo);
                    size = new double[4];
                    size = mShipPriceService.countSameSkuSize(size, productDo.getProductId(), 1);
                }
            }
        }
        if (packageDoList.size() < 1) {
            OrderOutputPackageDo packageDo = new OrderOutputPackageDo();
            packageDo.setLength(size[0]);
            packageDo.setWidth(size[1]);
            packageDo.setHeight(size[2]);
            packageDo.setWeight(size[3]);
            packageDoList.add(packageDo);
        }
        return packageDoList;
    }

    private Long getProductId(String sellerSku1, Long companyId) {
        final String sellerSku = sellerSku1.trim().replaceAll("\\n", "").replaceAll("　", "");
        LambdaQueryWrapper<ProductInfoDo> productWrapper = new LambdaQueryWrapper();
        productWrapper.eq(ProductInfoDo::getCompanyId, companyId);
        productWrapper.and(product -> {
            product.eq(ProductInfoDo::getCommoditySku, sellerSku).or()
                    .eq(ProductInfoDo::getStorageSku, sellerSku);
        });
        ProductInfoDo productInfoDo = productInfoDao.selectOne(productWrapper);
        if (productInfoDo == null) {
            QueryWrapper skuWrapper = new QueryWrapper();
            skuWrapper.eq("sub_sku", sellerSku);
            skuWrapper.eq("company_id", companyId);
            ProductSkuMapDo productSkuMapDo = productSkuMapDao.selectOne(skuWrapper);
            if (productSkuMapDo == null) {
                throw new BizExceptionI18("no.product.info_id", sellerSku);
            }
            return productSkuMapDo.getProductInfoId();
        } else {
            return productInfoDo.getId();
        }
    }

    private Long getSubProductId(String sellerSku, Long companyId) {
        QueryWrapper skuWrapper = new QueryWrapper();
        skuWrapper.eq("sub_sku", sellerSku);
        skuWrapper.eq("company_id", companyId);
        ProductSkuMapDo productSkuMapDo = productSkuMapDao.selectOne(skuWrapper);
        if (productSkuMapDo == null) {
            return 0L;
        }
        return productSkuMapDo.getProductInfoId();
    }


    /**
     * @param storageId
     * @param fbaStorageId
     * @param companyId
     * @return
     */
    @Override
    public SingleResult tracklist(Long storageId, Long fbaStorageId, Long companyId) {
        if (storageId == null) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_STORAGE);
        }
        if (fbaStorageId == null) {
            throw new BizExceptionI18(SysConstant.PLS_CHOOSE_OUT_FBA);
        }
        LambdaQueryWrapper<DicBusinessItemDo> doLambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<Map> mapLIst = new ArrayList<>();
        Map mapSagawa = new HashMap();
        mapSagawa.put("trackId", 8);
        mapSagawa.put("weight", 50);
        mapSagawa.put("type", 1);
        mapSagawa.put("size", 260);
        mapSagawa.put("trackName", dicBusinessItemDao.selectById(DicBusinessItemConstant.sagawaExpress).getDicItemValue());
        mapLIst.add(mapSagawa);
        doLambdaQueryWrapper.eq(DicBusinessItemDo::getDicBusinessId, DicBusinessConstant.fbaOrderOutPutTruck);
        List<DicBusinessItemDo> dicBusinessItemDoList = dicBusinessItemDao.selectList(doLambdaQueryWrapper);
        dicBusinessItemDoList.forEach(dicBusinessItemDo -> {
            LambdaQueryWrapper<FbaDimensDo> dimensDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            dimensDoLambdaQueryWrapper.eq(FbaDimensDo::getStorageId, storageId)
                    .eq(FbaDimensDo::getTrackId, dicBusinessItemDo.getId())
                    .orderByDesc(FbaDimensDo::getId)
                    .last("limit 1");
            FbaDimensDo fbaDimensDo = fbaDimensDao.selectOne(dimensDoLambdaQueryWrapper);
            Map map = new HashMap();
            map.put("track_id", dicBusinessItemDo.getId());
            map.put("weight", fbaDimensDo.getWeight());
            map.put("type", fbaDimensDo.getType());
            if (fbaDimensDo.getType() == 1) {
                map.put("size", fbaDimensDo.getSize());
            } else {
                map.put("volume", fbaDimensDo.getSize());
            }
            map.put("trackName", dicBusinessItemDo.getDicItemValue());
            mapLIst.add(map);
        });
        return SingleResult.success(mapLIst);
    }

    @Override
    public Object openApiUpdate(OpenAPIFbaOrderUpdateReq req, Long companyId, Long userId) {
        FbaOrderOutputUpdateReq updateReq = new FbaOrderOutputUpdateReq();
        BeanUtils.copyProperties(req, updateReq);
        //第三方api新增bean對象转化为OpenApiFbaOrderAddReq
        List<FbaOrderOutputPackageUpdateReq> packageUpdateReqList = new ArrayList<>();
        req.getPackageList().forEach(openApiFbaOrderOutputPackageAddReq -> {
            FbaOrderOutputPackageUpdateReq packageUpdateReq = new FbaOrderOutputPackageUpdateReq();
            List<FbaOrderOutputProductDetail> productAddReqList = new ArrayList<>();
            BeanUtils.copyProperties(openApiFbaOrderOutputPackageAddReq, packageUpdateReq);
            openApiFbaOrderOutputPackageAddReq.getProductList().forEach(orderOutputProductAddReq -> {
                FbaOrderOutputProductDetail productAddReq = new FbaOrderOutputProductDetail();
                BeanUtils.copyProperties(orderOutputProductAddReq, productAddReq);
                productAddReq.setProductId(getProductId(orderOutputProductAddReq.getCommoditySku(), companyId));
                productAddReqList.add(productAddReq);
            });
            packageUpdateReq.setProductList(productAddReqList);
            packageUpdateReqList.add(packageUpdateReq);
        });
        LambdaQueryWrapper<FbaStorageDo> fbaStorageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        fbaStorageDoLambdaQueryWrapper.eq(FbaStorageDo::getFbaCode, req.getFbaStorageCode());
        FbaStorageDo fbaStorageDo = fbaStorageDao.selectOne(fbaStorageDoLambdaQueryWrapper);
        if (fbaStorageDo == null) {
            return req.getFbaStorageCode() + "该FBA仓库不存在";
        }
        updateReq.setFbaStorageId(fbaStorageDo.getId());
        updateReq.setPackageList(packageUpdateReqList);
        update(updateReq, userId);
        return null;
    }

    @Override
    public Object openApiDelete(Long id, Long userId) {
        return delete(id, userId);
    }

    @Override
    public Object openApiDelete(String orderNumber, Long userId) {
        LambdaQueryWrapper<FbaOrderOutputDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FbaOrderOutputDo::getFbaOrderOutputNumber, orderNumber);
        FbaOrderOutputDo entityDo = dao.selectOne(wrapper);
        if (entityDo == null) {
            throw new BizExceptionI18("order.detail.notfound.or.delete");
        }
        return delete(entityDo.getId(), userId);
    }

    @Override
    public FbaOrderOutputDetailRes apiDetail(Long id) {
        return detail(id, false);
    }

    @Override
    public FbaOrderOutputDetailRes apiDetail(String orderNumber) {
        return detail(orderNumber);
    }

    @Override
    public String fbaStorageOpenAdd(FbaOrderOutputOpenAddReq req, Long userId) {
        sufficientFundsCheck(req.getCompanyId());
        if (req.getShopId() == null) {
            throw new BizExceptionI18("order.no.shop");
        }
        if (req.getStorageId() == null) {
            throw new BizExceptionI18("order.no.storage");
        }
        if (req.getPackageList() == null ||
                req.getPackageList().size() < 1) {
            throw new BizExceptionI18("order.no.product");
        }
        if (StringUtils.isNotBlank(req.getFbaStorageCode())) {
            FbaStorageDo fbaStorageDo = fbaStorageDao.selectOne(new LambdaQueryWrapper<FbaStorageDo>().eq(FbaStorageDo::getFbaCode, req.getFbaStorageCode()));
            if (fbaStorageDo != null) {
                req.setFbaStorageId(fbaStorageDo.getId());
                req.setStorageType("fba");
            } else {
                req.setStorageType("own");
            }
        } else {
            req.setStorageType("own");
            if (StringUtils.isBlank(req.getAddress())) {
                throw new BizExceptionI18("order.no.address");
            }
            if (StringUtils.isBlank(req.getPostCode())) {
                throw new BizExceptionI18("order.no.postcode");
            }
            if (StringUtils.isBlank(req.getReceiverName())) {
                throw new BizExceptionI18("order.no.receivername");
            }
            if (StringUtils.isBlank(req.getTelPhone())) {
                throw new BizExceptionI18("order.no.telphone");
            }
        }
        if (req.getTrackId() == null) {
            FbaOrderOutputComputationalCostsReq costsReq = new FbaOrderOutputComputationalCostsReq();
            if (req.getFbaStorageId() != null) {
                costsReq.setFbaStorageId(req.getFbaStorageId());
            } else {
                costsReq.setPostCode(req.getPostCode());
            }
            costsReq.setStorageId(req.getStorageId());
            costsReq.setPackageAddReqList(req.getPackageList());
            List<Map> mapList = computationalCosts(costsReq, req.getCompanyId());
            List<Map> collect = mapList.stream().filter(map -> (Boolean) map.get("flag"))
                    .sorted((o1, o2) -> (int) ((Double) o1.get("shipFee") - (Double) o2.get("shipFee"))).collect(Collectors.toList());
            if (collect.size() > 0) {
                req.setTrackId((Long) collect.get(0).get("trackId"));
                req.setShipFee((Double) collect.get(0).get("shipFee"));
                req.setOperateFee((Integer) collect.get(0).get("operateFee"));
            }
        }
        if (req.getTrackId().equals(DicBusinessItemConstant.fbaTrackNameGreenBox) &&
                (req.getFbaStorageId() == null || req.getFbaStorageId() == 34 || req.getFbaStorageId() == 35 ||
                        (req.getFbaStorageId() >= 80 && req.getFbaStorageId() <= 86))) {
            throw new BizExceptionI18("no.support.feiyun.letian");
        }
        if (req.getTrackId().equals(DicBusinessItemConstant.fbaTrackName2t) && req.getFbaStorageId() != null &&
                ((req.getFbaStorageId() >= 16 && req.getFbaStorageId() <= 19) || req.getFbaStorageId() == 33 || req.getFbaStorageId() == 14
                        || req.getFbaStorageId() == 42 || req.getFbaStorageId() == 56 || req.getFbaStorageId() == 70)) {
            throw new BizExceptionI18("no.support.2t.fbaStorage.list");
        }
        FbaOrderOutputDo entityDo = new FbaOrderOutputDo();
        if (req.getStorageType().equals(SysConstant.FBA_ADDRESS)) {
            FbaStorageDo fbaStorageDo = fbaStorageDao.selectById(req.getFbaStorageId());
            if (StringUtils.isBlank(req.getAddress())) {
                req.setAddress(fbaStorageDo.getAddress());
            }
            if (StringUtils.isBlank(req.getPostCode())) {
                req.setPostCode(fbaStorageDo.getPostCode());
            }
            if (StringUtils.isBlank(req.getReceiverName())) {
                req.setReceiverName(fbaStorageDo.getFbaName());
            }
            if (StringUtils.isBlank(req.getTelPhone())) {
                req.setTelPhone(fbaStorageDo.getTelPhone());
            }
        } else {
            ShippingAddressDo fbaStorageDo = shippingAddressDao.selectById(req.getFbaStorageId());
            if (fbaStorageDo != null) {
                if (StringUtils.isBlank(req.getAddress())) {
                    req.setAddress(fbaStorageDo.getAddress());
                }
                if (StringUtils.isBlank(req.getPostCode())) {
                    req.setPostCode(fbaStorageDo.getPostCode());
                }
                if (StringUtils.isBlank(req.getReceiverName())) {
                    req.setReceiverName(fbaStorageDo.getCompanyName());
                }
                if (StringUtils.isBlank(req.getTelPhone())) {
                    req.setTelPhone(fbaStorageDo.getTelPhone());
                }
            }
        }
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setShipFee(req.getShipFee());
        if (StringUtils.isNotBlank(req.getDeliveryDate())) {
            entityDo.setDeliveryDate(TimeUtils.parseDate(req.getDeliveryDate()));
        }
        handlerAddBefore(entityDo, userId);
        if (StringUtils.isNotBlank(req.getStorageType())) {
            entityDo.setStorageType(req.getStorageType());
        } else {
            entityDo.setStorageType(SysConstant.OWN_ADDRESS);
        }
        dao.insert(entityDo);

        try {
            if (StringUtils.isNotBlank(req.getFileUrl())) {
                Long fileId = fileService.uploadExcelImage(req.getFileUrl(), 1L);
                entityDo.setFileId(fileId);
            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(req.getFileUrl())) {
            Long productFileId = null;
            try {
                productFileId = fileService.uploadExcelImage(req.getProductFileUrl(), 1L);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            entityDo.setProductFileId(productFileId);
        }
        if (StringUtils.isNotBlank(req.getFileUrl())) {
            Long otherFileId = null;
            try {
                otherFileId = fileService.uploadExcelImage(req.getOtherFileUrl(), 1L);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            entityDo.setOtherFileId(otherFileId);
        }

        handlerFbaStorageAdd(entityDo, entityDo.getFileId(), entityDo.getProductFileId(), req.getTrackId(), req.getPackageList(), userId);
        entityDo.setFbaOrderOutputNumber(OrderCodeUtil.getFbaOrderOutputNumber(entityDo.getId()));
        entityDo.setTrackId(req.getTrackId());
        //todo 判断是否有足额
        verfiyCurrentAmount(entityDo.getOutFee() + entityDo.getShipFee() + entityDo.getOperateFee() + entityDo.getTaxFee(), entityDo.getCompanyId(), entityDo.getId());
        dao.updateById(entityDo);
        //计算费用
//        handlerFee(entityDo);

        //日志操作
        operateRecordService.operateAddRecord(SysConstant.OPERATE_API_CREATE_FBA, entityDo.getId(), userId, 6);

        LambdaQueryWrapper<OrderInputDo> orderInputWrapper = new LambdaQueryWrapper<>();
        orderInputWrapper.eq(OrderInputDo::getOrderInputNumber, entityDo.getOrderInputNumber());
        OrderInputDo orderInputDo = orderInputDao.selectOne(orderInputWrapper);
        if (orderInputDo != null) {
            if (orderInputDo.getStatus().equals(DicBusinessItemConstant.inPutStorage)) {
                orderInputService.handlerStockCount(orderInputDo, userId);
            }
            orderInputDo.setStatus(DicBusinessItemConstant.inPutTurnFba);
            orderInputDo.setUpdateBy(userId);
            orderInputDo.setUpdateTime(new Date());
            orderInputDo.setInputBy(userId);
            orderInputDo.setInputTime(new Date());
            operateRecordService.operateAddRecord(SysConstant.OPERATE_TURN_FBA_ORDER, orderInputDo.getId(), userId, 2);

            orderInputDao.updateById(orderInputDo);
        }
        return entityDo.getFbaOrderOutputNumber();
    }
}
